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.
1029 lines
34 KiB
1029 lines
34 KiB
1 year ago
|
<?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__).'/traits/TableTrait.php';
|
||
|
require_once dirname(__FILE__).'/behaviors/CMessageBehavior.php';
|
||
|
|
||
|
/**
|
||
|
* @backup sessions
|
||
|
*
|
||
|
* @backupConfig
|
||
|
*/
|
||
|
class testFormSetup extends CWebTest {
|
||
|
|
||
|
use TableTrait;
|
||
|
|
||
|
/**
|
||
|
* Attach MessageBehavior to the test.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getBehaviors() {
|
||
|
return [
|
||
|
'class' => CMessageBehavior::class
|
||
|
];
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @backup config
|
||
|
*/
|
||
|
public function testFormSetup_welcomeSectionLayout() {
|
||
|
$this->page->login()->open('setup.php')->waitUntilReady();
|
||
|
|
||
|
// Check Welcome section.
|
||
|
$this->assertEquals("Welcome to\nZabbix ".ZABBIX_EXPORT_VERSION, $this->query('xpath://div[@class="setup-title"]')->one()->getText());
|
||
|
$this->checkSections('Welcome');
|
||
|
$form = $this->query('xpath://form')->asForm()->one();
|
||
|
$language_field = $form->getField('Default language');
|
||
|
$this->assertEquals('English (en_US)', $language_field->getValue());
|
||
|
$hint_text = 'You are not able to choose some of the languages, because locales for them are not installed '.
|
||
|
'on the web server.';
|
||
|
$this->assertEquals($hint_text, $this->query('class:hint-box')->one()->getText());
|
||
|
$this->checkButtons('first section');
|
||
|
|
||
|
$this->assertScreenshot($form, 'Welcome_En');
|
||
|
|
||
|
// Check that default language can be changed.
|
||
|
$language_field->fill('Russian (ru_RU)');
|
||
|
$this->page->refresh()->waitUntilReady();
|
||
|
$this->assertEquals("Добро пожаловать в\nZabbix ".ZABBIX_EXPORT_VERSION, $this->query('xpath://div[@class="setup-title"]')->one()->getText());
|
||
|
|
||
|
$this->checkButtons('russian');
|
||
|
$this->assertScreenshotExcept($form, $this->query('id:default-lang')->one(), 'Welcome_Rus');
|
||
|
}
|
||
|
|
||
|
public function testFormSetup_prerequisitesSectionLayout() {
|
||
|
$this->page->login()->open('setup.php')->waitUntilReady();
|
||
|
$this->query('button:Next step')->one()->click();
|
||
|
|
||
|
// Check Pre-requisites section.
|
||
|
$this->checkPageTextElements('Check of pre-requisites');
|
||
|
$headers = $this->query('class:list-table')->asTable()->one()->getHeadersText();
|
||
|
$this->assertEquals(['', 'Current value', 'Required', ''], $headers);
|
||
|
|
||
|
$prerequisites = [
|
||
|
'PHP version',
|
||
|
'PHP option "memory_limit"',
|
||
|
'PHP option "post_max_size"',
|
||
|
'PHP option "upload_max_filesize"',
|
||
|
'PHP option "max_execution_time"',
|
||
|
'PHP option "max_input_time"',
|
||
|
'PHP databases support',
|
||
|
'PHP bcmath',
|
||
|
'PHP mbstring',
|
||
|
'PHP option "mbstring.func_overload"',
|
||
|
'PHP sockets',
|
||
|
'PHP gd',
|
||
|
'PHP gd PNG support',
|
||
|
'PHP gd JPEG support',
|
||
|
'PHP gd GIF support',
|
||
|
'PHP gd FreeType support',
|
||
|
'PHP libxml',
|
||
|
'PHP xmlwriter',
|
||
|
'PHP xmlreader',
|
||
|
'PHP LDAP',
|
||
|
'PHP OpenSSL',
|
||
|
'PHP ctype',
|
||
|
'PHP session',
|
||
|
'PHP option "session.auto_start"',
|
||
|
'PHP gettext',
|
||
|
'PHP option "arg_separator.output"'
|
||
|
];
|
||
|
$this->assertTableDataColumn($prerequisites, '');
|
||
|
$this->checkSections('Check of pre-requesties');
|
||
|
$this->checkButtons();
|
||
|
|
||
|
global $DB;
|
||
|
$php_version = $this->query('xpath://td[text()="PHP version"]/following-sibling::td')->one();
|
||
|
$this->assertScreenshotExcept($this->query('xpath://form')->one(), $php_version, 'Prerequisites_'.$DB['TYPE']);
|
||
|
}
|
||
|
|
||
|
public function testFormSetup_dbConnectionSectionLayout() {
|
||
|
$this->openSpecifiedSection('Configure DB connection');
|
||
|
$db_parameters = $this->getDbParameters();
|
||
|
|
||
|
// Check Configure DB connection section.
|
||
|
$fields = [
|
||
|
'Database port' => '0',
|
||
|
'Database name' => 'zabbix',
|
||
|
'User' => 'zabbix',
|
||
|
'Password' => ''
|
||
|
];
|
||
|
$fields['Database host'] = ($db_parameters['Database type'] === 'PostgreSQL') ?
|
||
|
'localhost' : $db_parameters['Database host'];
|
||
|
$text = 'Please create database manually, and set the configuration parameters for connection to this database. '.
|
||
|
'Press "Next step" button when done.';
|
||
|
$this->checkPageTextElements('Configure DB connection', $text);
|
||
|
$form = $this->query('xpath://form')->asForm()->one();
|
||
|
|
||
|
// Check input fields in Configure DB connection section for each DB type.
|
||
|
$db_types = $form->getField('Database type')->getOptions()->asText();
|
||
|
foreach ($db_types as $db_type) {
|
||
|
$form->getField('Database type')->select($db_type);
|
||
|
$form->invalidate();
|
||
|
switch ($db_type) {
|
||
|
case 'Oracle':
|
||
|
$this->assertFalse($form->query('xpath://label[text()="Database schema"]')->one(false)->isDisplayed());
|
||
|
$this->assertFalse($form->query('xpath://label[text()="Database TLS encryption"]')->one(false)->isDisplayed());
|
||
|
break;
|
||
|
|
||
|
case 'MySQL':
|
||
|
// Check that Database schema field is not available.
|
||
|
$this->assertFalse($form->query('xpath://label[text()="Database schema"]')->one(false)->isDisplayed());
|
||
|
// Check TLS fields if such should be displayed.
|
||
|
if ($db_parameters['Database host'] === 'localhost') {
|
||
|
$tls_text = 'Connection will not be encrypted because it uses a socket file (on Unix) or shared '.
|
||
|
'memory (Windows).';
|
||
|
$this->assertEquals($tls_text, $form->query('id:tls_encryption_hint')->one()->getText());
|
||
|
}
|
||
|
else {
|
||
|
$form->getField('Database host')->fill($db_parameters['Database host']);
|
||
|
$this->page->removeFocus();
|
||
|
$this->checkTlsFieldsLayout();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'PostgreSQL':
|
||
|
// Check that Database Schema and Database TLS encryption fields are visible.
|
||
|
$schema_field = $form->getField('Database schema');
|
||
|
$this->assertEquals(255, $schema_field->getAttribute('maxlength'));
|
||
|
$this->checkTlsFieldsLayout();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
foreach ($fields as $field_name => $field_value) {
|
||
|
$maxlength = ($field_name === 'Database port') ? 5 : 255;
|
||
|
$field = $form->getField($field_name);
|
||
|
$this->assertEquals($field_value, $field->getValue());
|
||
|
$this->assertEquals($maxlength, $field->getAttribute('maxlength'));
|
||
|
|
||
|
}
|
||
|
// Array of fields to be skipped by the screenshot check.
|
||
|
$skip_db_fields = [];
|
||
|
foreach(['Database host', 'Database name', 'Store credentials in'] as $skip_field) {
|
||
|
$skip_db_fields[] = $form->getField($skip_field);
|
||
|
}
|
||
|
// Check screenshot for "Store credentials in" = Plain text.
|
||
|
$this->assertScreenshotExcept($form, $skip_db_fields, 'ConfigureDB_plainText_'.$db_type);
|
||
|
|
||
|
// Check 'Store credentials in' field, switch to Vault and check Vault rellated fields.
|
||
|
$credentials_field = $form->getField('Store credentials in');
|
||
|
$this->assertEquals('Plain text', $credentials_field->getSelected());
|
||
|
|
||
|
// All vault fields labels.
|
||
|
$labels = [
|
||
|
'Vault API endpoint',
|
||
|
'Vault secret path',
|
||
|
'Vault authentication token',
|
||
|
'Vault secret query string',
|
||
|
'Vault certificates'
|
||
|
];
|
||
|
foreach ($labels as $label_name) {
|
||
|
$this->assertFalse($form->getField($label_name)->isVisible());
|
||
|
}
|
||
|
|
||
|
// HashiCorp and Cyberark vault fields.
|
||
|
$vaults = [
|
||
|
'HashiCorp Vault' => [
|
||
|
'Vault API endpoint' => 'https://localhost:8200',
|
||
|
'Vault secret path' => 'path/to/secret',
|
||
|
'Vault authentication token' => ''
|
||
|
],
|
||
|
'CyberArk Vault' => [
|
||
|
'Vault API endpoint' => 'https://localhost:1858',
|
||
|
'Vault secret query string' => 'AppID=foo&Query=Safe=bar;Object=buzz',
|
||
|
'SSL certificate file' => 'conf/certs/cyberark-cert.pem',
|
||
|
'SSL key file' => 'conf/certs/cyberark-key.pem'
|
||
|
]
|
||
|
];
|
||
|
|
||
|
// Check layout when "Store credentials in" is set to "HashiCorp Vault" or "CyberArk Vault".
|
||
|
foreach ($vaults as $vault => $vault_fields) {
|
||
|
$credentials_field->select($vault);
|
||
|
$form->invalidate();
|
||
|
|
||
|
if ($vault === 'CyberArk Vault') {
|
||
|
$form->fill(['Vault certificates' => true]);
|
||
|
}
|
||
|
|
||
|
foreach (['User', 'Password'] as $parameter) {
|
||
|
$this->assertFalse($form->getField($parameter)->isVisible());
|
||
|
}
|
||
|
|
||
|
foreach ($vault_fields as $field_name => $parameter) {
|
||
|
$vault_maxlength = ($field_name === 'Vault API endpoint' || $field_name === 'Vault secret path') ? 255 : 2048;
|
||
|
$field = $form->getField($field_name);
|
||
|
$this->assertEquals($vault_maxlength, $field->getAttribute('maxlength'));
|
||
|
if (in_array($field_name, ['Vault secret query string', 'Vault secret path'])) {
|
||
|
$this->assertEquals($parameter, $field->getAttribute('placeholder'));
|
||
|
}
|
||
|
else {
|
||
|
$this->assertEquals($parameter, $field->getValue());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Array of fields to be skipped by the screenshot check.
|
||
|
$skip_fields_vault = [];
|
||
|
|
||
|
foreach(['Database host', 'Database name', 'Store credentials in'] as $skip_field) {
|
||
|
$skip_fields_vault[] = $form->getField($skip_field);
|
||
|
}
|
||
|
|
||
|
// Check screenshot for "Store credentials in" = Vault.
|
||
|
$this->assertScreenshotExcept($form, $skip_fields_vault, 'ConfigureDB_Vault_'.$db_type.$vault);
|
||
|
}
|
||
|
|
||
|
$credentials_field->select('Plain text');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @backup config
|
||
|
*/
|
||
|
public function testFormSetup_settingsSection() {
|
||
|
// Open the Pre-installation summary section.
|
||
|
$this->openSpecifiedSection('Settings');
|
||
|
// Check GUI settings section.
|
||
|
$this->checkPageTextElements('Settings');
|
||
|
$this->checkButtons();
|
||
|
$form = $this->query('xpath://form')->asForm()->one();
|
||
|
// Check layout via screenshot for default theme.
|
||
|
$this->assertScreenshotExcept($form, $this->query('id:label-default-timezone')->one(), 'GUISettings_Default');
|
||
|
|
||
|
// Check Zabbix server name field.
|
||
|
$server_name = $form->getField('Zabbix server name');
|
||
|
$this->assertEquals(255, $server_name->getAttribute('maxlength'));
|
||
|
$this->assertEquals('', $server_name->getValue());
|
||
|
|
||
|
// Check timezone field.
|
||
|
$timezones_field = $form->getField('Default time zone');
|
||
|
$timezones = $timezones_field->getOptions()->asText();
|
||
|
|
||
|
// Note that count of available timezones may differ based on the local environment configuration.
|
||
|
$this->assertEquals(420, count($timezones));
|
||
|
|
||
|
foreach (['System', 'Europe/Riga'] as $timezone_value) {
|
||
|
$timezone = CDateTimeHelper::getTimeZoneFormat($timezone_value);
|
||
|
$this->assertContains($timezone, $timezones);
|
||
|
}
|
||
|
// Select a certain timezone.
|
||
|
$form->getField('Default time zone')->select(CDateTimeHelper::getTimeZoneFormat('Europe/Riga'));
|
||
|
|
||
|
// Check Default theme field.
|
||
|
$themes = $form->getField('Default theme');
|
||
|
$this->assertEquals(['Blue', 'Dark', 'High-contrast light', 'High-contrast dark'], $themes->getOptions()->asText());
|
||
|
// Select Dark theme.
|
||
|
$form->getField('Default theme')->select('Dark');
|
||
|
|
||
|
// Check that default theme has changed.
|
||
|
$stylesheet = $this->query('xpath://link[@rel="stylesheet"]')->one();
|
||
|
$parts = explode('/', $stylesheet->getAttribute('href'));
|
||
|
$this->assertContains('dark-theme.css', explode('?', end($parts)));
|
||
|
// Check layout via screenshot for dark theme.
|
||
|
$this->assertScreenshotExcept($form, $this->query('id:label-default-timezone')->one(), 'GUISettings_Dark');
|
||
|
|
||
|
// Complete the setup and check in DB that the default timezone was applied.
|
||
|
$this->query('button:Next step')->one()->click();
|
||
|
$this->query('button:Next step')->one()->click();
|
||
|
$this->query('button:Finish')->one()->click();
|
||
|
$db_values = CDBHelper::getRow('SELECT default_theme, default_timezone FROM config');
|
||
|
$this->assertEquals(['dark-theme', 'Europe/Riga'], array_values($db_values));
|
||
|
}
|
||
|
|
||
|
public function testFormSetup_summarySection() {
|
||
|
$this->openSpecifiedSection('Pre-installation summary');
|
||
|
|
||
|
// Check that Zabbix server name field is not displayed if it is not populated.
|
||
|
$this->assertFalse($this->query('xpath://span[text()="Zabbix server name"]')->one(false)->isValid());
|
||
|
$this->query('button:Back')->one()->click();
|
||
|
// Fill in the Zabbix server name field and proceed with checking Pre-installation summary.
|
||
|
$this->query('id:setup-form')->asForm()->one()->getField('Zabbix server name')->fill('Zabbix server name');
|
||
|
$this->query('button:Next step')->one()->click();
|
||
|
$db_parameters = $this->getDbParameters();
|
||
|
$text = 'Please check configuration parameters. If all is correct, press "Next step" button, or "Back" button '.
|
||
|
'to change configuration parameters.';
|
||
|
$this->checkPageTextElements('Pre-installation summary', $text);
|
||
|
|
||
|
$summary_fields = [
|
||
|
'Database server' => $db_parameters['Database host'],
|
||
|
'Database name' => $db_parameters['Database name'],
|
||
|
'Database user' => $db_parameters['User'],
|
||
|
'Database password' => '******',
|
||
|
'Zabbix server name' => 'Zabbix server name'
|
||
|
];
|
||
|
|
||
|
if ($db_parameters['Database type'] === 'PostgreSQL') {
|
||
|
$summary_fields['Database type'] = 'PostgreSQL';
|
||
|
$summary_fields['Database schema'] = '';
|
||
|
$summary_fields['Database TLS encryption'] = 'true';
|
||
|
}
|
||
|
else {
|
||
|
$summary_fields['Database type'] = 'MySQL';
|
||
|
$this->assertFalse($this->query('xpath://span[text()="Database schema"]')->one(false)->isValid());
|
||
|
$summary_fields['Database TLS encryption'] = ($db_parameters['Database host'] === 'localhost') ? 'false' : 'true';
|
||
|
}
|
||
|
$summary_fields['Database port'] = ($db_parameters['Database port'] === '0') ? 'default' : $db_parameters['Database port'];
|
||
|
foreach ($summary_fields as $field_name => $value) {
|
||
|
$xpath = 'xpath://span[text()='.CXPathHelper::escapeQuotes($field_name).']/../../div[@class="table-forms-td-right"]';
|
||
|
// Assert contains is used as Password length can differ.
|
||
|
if ($field_name === 'Database password') {
|
||
|
$this->assertStringContainsString($value, $this->query($xpath)->one()->getText());
|
||
|
}
|
||
|
else {
|
||
|
$this->assertEquals($value, $this->query($xpath)->one()->getText());
|
||
|
}
|
||
|
}
|
||
|
$this->checkButtons();
|
||
|
|
||
|
// Check screenshot of the Pre-installation summary section.
|
||
|
$skip_fields = [];
|
||
|
foreach(['Database server', 'Database port', 'Database name'] as $skip_field) {
|
||
|
$xpath = 'xpath://span[text()='.CXPathHelper::escapeQuotes($skip_field).']/../../div[@class="table-forms-td-right"]';
|
||
|
$skip_fields[] = $this->query($xpath)->one();
|
||
|
}
|
||
|
$this->assertScreenshotExcept($this->query('xpath://form')->one(), $skip_fields, 'PreInstall_'.$db_parameters['Database type']);
|
||
|
}
|
||
|
|
||
|
public function testFormSetup_installSection() {
|
||
|
$this->openSpecifiedSection('Install');
|
||
|
$this->checkPageTextElements('Install', 'Configuration file "conf/zabbix.conf.php" created.');
|
||
|
$this->assertEquals('Congratulations! You have successfully installed Zabbix frontend.',
|
||
|
$this->query('class:green')->one()->getText());
|
||
|
$this->checkButtons('last section');
|
||
|
$this->assertScreenshotExcept($this->query('xpath://form')->one(), $this->query('xpath://p')->one(), 'Install');
|
||
|
|
||
|
// Check that Dashboard view is opened after completing the form.
|
||
|
$this->query('button:Finish')->one()->click();
|
||
|
$this->page->waitUntilReady();
|
||
|
$this->assertStringContainsString('index.php', $this->page->getCurrentURL());
|
||
|
}
|
||
|
|
||
|
public function getDbConnectionDetails() {
|
||
|
$provider = [
|
||
|
// Incorrect DB host.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Database host',
|
||
|
'value'=> 'incorrect_DB_host'
|
||
|
],
|
||
|
'mysql_error' => 'php_network_getaddresses: getaddrinfo failed: Name or service not known'
|
||
|
]
|
||
|
],
|
||
|
// Partially non-numeric port number.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Database port',
|
||
|
'value' => '123aaa'
|
||
|
],
|
||
|
'check_port' => 123,
|
||
|
'mysql_error' => 'Connection refused'
|
||
|
]
|
||
|
],
|
||
|
// Large port number.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Database port',
|
||
|
'value' => '99999'
|
||
|
],
|
||
|
'error_details' => 'Incorrect value "99999" for "Database port" field: must be between 0 and 65535.'
|
||
|
]
|
||
|
],
|
||
|
// Incorrect DB name.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Database name',
|
||
|
'value' => 'Wrong database name'
|
||
|
],
|
||
|
'mysql_error' => "Unknown database 'Wrong database name'"
|
||
|
]
|
||
|
],
|
||
|
// Incorrect DB schema for PostgreSQL.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Database schema',
|
||
|
'value' => 'incorrect schema'
|
||
|
],
|
||
|
'error_details' => 'Unable to determine current Zabbix database version: the table "dbversion" was not found.'
|
||
|
]
|
||
|
],
|
||
|
// Incorrect user name.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'User',
|
||
|
'value' => 'incorrect user name'
|
||
|
],
|
||
|
'mysql_error' => 'Access denied for user'
|
||
|
]
|
||
|
],
|
||
|
// Set incorrect password.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Password',
|
||
|
'value' => 'this_password_is_incorrect'
|
||
|
],
|
||
|
'mysql_error' => 'Access denied for user'
|
||
|
]
|
||
|
],
|
||
|
// Empty "Database TLS CA file" field.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Database TLS CA file',
|
||
|
'value' => ''
|
||
|
],
|
||
|
'tls_encryption' => true,
|
||
|
'error_details' => 'Incorrect file path for "Database TLS CA file": .'
|
||
|
]
|
||
|
],
|
||
|
// Wrong "Database TLS CA file" field format.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Database TLS CA file',
|
||
|
'value' => '123456'
|
||
|
],
|
||
|
'tls_encryption' => true,
|
||
|
'error_details' => 'Incorrect file path for "Database TLS CA file": 123456.'
|
||
|
]
|
||
|
],
|
||
|
// Wrong "Database TLS CA file" path leads to wrong file.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Database TLS CA file',
|
||
|
'value' => '/etc/apache2/magic'
|
||
|
],
|
||
|
'tls_encryption' => true,
|
||
|
'mysql_error' => 'Error connecting to database. Empty cipher.'
|
||
|
]
|
||
|
],
|
||
|
// Wrong "Database TLS key file" field format.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Database TLS key file',
|
||
|
'value' => '123'
|
||
|
],
|
||
|
'tls_encryption' => true,
|
||
|
'fill_ca_file' => true,
|
||
|
'error_details' => 'Incorrect file path for "Database TLS key file": 123.'
|
||
|
]
|
||
|
],
|
||
|
// Wrong "Database TLS key file" path leads to wrong file.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Database TLS key file',
|
||
|
'value' => '/etc/apache2/magic'
|
||
|
],
|
||
|
'tls_encryption' => true,
|
||
|
'fill_ca_file' => true,
|
||
|
'mysql_error' => 'Error connecting to database. Empty cipher.'
|
||
|
]
|
||
|
],
|
||
|
// Wrong "Database TLS certificate file" field format.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Database TLS certificate file',
|
||
|
'value' => '123'
|
||
|
],
|
||
|
'tls_encryption' => true,
|
||
|
'fill_ca_file' => true,
|
||
|
'error_details' => 'Incorrect file path for "Database TLS certificate file": 123.'
|
||
|
]
|
||
|
],
|
||
|
// Wrong "Database TLS certificate file" path leads to wrong file.
|
||
|
[
|
||
|
[
|
||
|
'expected' => TEST_BAD,
|
||
|
'field' => [
|
||
|
'name' => 'Database TLS certificate file',
|
||
|
'value' => '/etc/apache2/magic'
|
||
|
],
|
||
|
'tls_encryption' => true,
|
||
|
'fill_ca_file' => true,
|
||
|
'mysql_error' => 'Error connecting to database. Empty cipher.'
|
||
|
]
|
||
|
],
|
||
|
// With "Database TLS encryption" set.
|
||
|
[
|
||
|
[
|
||
|
'field' => [
|
||
|
'name' => 'Database TLS encryption',
|
||
|
'value' => true
|
||
|
]
|
||
|
]
|
||
|
],
|
||
|
// Non-numeric port.
|
||
|
[
|
||
|
[
|
||
|
'field' => [
|
||
|
'name' => 'Database port',
|
||
|
'value' => 'aaa1'
|
||
|
],
|
||
|
'check_port' => 0
|
||
|
]
|
||
|
],
|
||
|
// Non-default port.
|
||
|
[
|
||
|
[
|
||
|
'field' => [
|
||
|
'name' => 'Database port',
|
||
|
'value' => 'should_be_changed'
|
||
|
],
|
||
|
'change_port' => true
|
||
|
]
|
||
|
]
|
||
|
];
|
||
|
|
||
|
// MySQL database error depends on php version.
|
||
|
$mapping = [
|
||
|
'Error connecting to database. Empty cipher.' => [
|
||
|
'8.1.0' => '(trying to connect via (null))'
|
||
|
],
|
||
|
'php_network_getaddresses: getaddrinfo failed: Name or service not known' => [
|
||
|
'8.1.0' => 'php_network_getaddresses: getaddrinfo for incorrect_DB_host failed: Name or service not known'
|
||
|
]
|
||
|
];
|
||
|
|
||
|
foreach ($provider as &$data) {
|
||
|
if (array_key_exists('mysql_error', $data[0]) && array_key_exists($data[0]['mysql_error'], $mapping)) {
|
||
|
foreach ($mapping[$data[0]['mysql_error']] as $version => $map) {
|
||
|
if (version_compare(phpversion(), $version, '<')) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$data[0]['mysql_error'] = $map;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
unset($data);
|
||
|
|
||
|
return $provider;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dataProvider getDbConnectionDetails
|
||
|
*/
|
||
|
public function testFormSetup_dbConfigSectionParameters($data) {
|
||
|
// Prepare array with DB parameter values.
|
||
|
$db_parameters = $this->getDbParameters();
|
||
|
$db_parameters[$data['field']['name']] = $data['field']['value'];
|
||
|
|
||
|
// Use default database port if specified in data provider.
|
||
|
if (array_key_exists('change_port', $data)) {
|
||
|
$db_parameters['Database port'] = ($db_parameters['Database type'] === 'PostgreSQL') ? 5432 : 3306;
|
||
|
}
|
||
|
|
||
|
// Skip the case with invalid DB schema if DB type is MySQL.
|
||
|
if ($data['field']['name'] === 'Database schema' && $db_parameters['Database type'] === 'MySQL') {
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
// Open "Configure DB connection" section.
|
||
|
$this->openSpecifiedSection('Configure DB connection');
|
||
|
|
||
|
// Fill Database connection parameters.
|
||
|
$form = $this->query('xpath://form')->asForm()->one();
|
||
|
// Fill required TLS rellated field values.
|
||
|
if (array_key_exists('tls_encryption', $data)) {
|
||
|
// TLS fields are not present in case if DB type = MySQL and for DB host = localhost.
|
||
|
if (($db_parameters['Database type'] === 'MySQL' && $db_parameters['Database host'] === 'localhost')) {
|
||
|
$tls_text = 'Connection will not be encrypted because it uses a socket file (on Unix) or shared memory (Windows).';
|
||
|
$this->assertEquals($tls_text, $form->query('id:tls_encryption_hint')->one()->getText());
|
||
|
// Skip data provider as TLS encryption fields are not visible.
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
else {
|
||
|
$form->getField('Database type')->fill($db_parameters['Database type']);
|
||
|
$form->getField('Database host')->fill($db_parameters['Database host']);
|
||
|
$this->page->removeFocus();
|
||
|
$form->getField('Database TLS encryption')->check();
|
||
|
$form->query('xpath:.//label[@for="verify_certificate"]/span')->asCheckbox()->one()->check();
|
||
|
if (array_key_exists('fill_ca_file', $data)) {
|
||
|
$form->getField('Database TLS CA file')->fill('/etc/apache2/magic');
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$form->fill($db_parameters);
|
||
|
|
||
|
// Check that port number was trimmed after removing focus, starting with 1st non-numeric symbol.
|
||
|
if ($data['field']['name'] === 'Database port') {
|
||
|
$this->page->removeFocus();
|
||
|
}
|
||
|
if (array_key_exists('check_port', $data)) {
|
||
|
$this->assertEquals($data['check_port'], $form->getField('Database port')->getValue());
|
||
|
}
|
||
|
|
||
|
// Check the outcome for the specified database configuration.
|
||
|
$this->query('button:Next step')->one()->click();
|
||
|
if (CTestArrayHelper::get($data, 'expected', TEST_GOOD) === TEST_BAD) {
|
||
|
// Define the reference error message details and assert error message.
|
||
|
if (array_key_exists('error_details', $data)) {
|
||
|
$error_details = $data['error_details'];
|
||
|
}
|
||
|
else {
|
||
|
$error_details = ($db_parameters['Database type'] === 'MySQL') ? $data['mysql_error'] :
|
||
|
'Error connecting to database.';
|
||
|
}
|
||
|
$this->assertMessage(TEST_BAD, 'Cannot connect to the database.', $error_details);
|
||
|
}
|
||
|
else {
|
||
|
$this->assertEquals('Settings', $this->query('xpath://h1')->one()->getText());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function getDbConnectionDetailsForTls() {
|
||
|
return [
|
||
|
// TLS available when IP address is used as host name - MySQL.
|
||
|
[
|
||
|
[
|
||
|
'fields' => [
|
||
|
'Database type' => 'MySQL',
|
||
|
'Database host'=> '127.0.0.1'
|
||
|
],
|
||
|
'tls_displayed' => true
|
||
|
]
|
||
|
],
|
||
|
// TLS available when string is used as host name - MySQL.
|
||
|
[
|
||
|
[
|
||
|
'fields' => [
|
||
|
'Database type' => 'MySQL',
|
||
|
'Database host'=> 'abc'
|
||
|
],
|
||
|
'tls_displayed' => true
|
||
|
]
|
||
|
],
|
||
|
// TLS available when empty space is used as host name - MySQL.
|
||
|
[
|
||
|
[
|
||
|
'fields' => [
|
||
|
'Database type' => 'MySQL',
|
||
|
'Database host'=> ' '
|
||
|
],
|
||
|
'tls_displayed' => true
|
||
|
]
|
||
|
],
|
||
|
// TLS NOT available when host name is empty - MySQL.
|
||
|
[
|
||
|
[
|
||
|
'fields' => [
|
||
|
'Database type' => 'MySQL',
|
||
|
'Database host'=> ''
|
||
|
]
|
||
|
]
|
||
|
],
|
||
|
// TLS NOT available when host name is equal to "localhost" - MySQL.
|
||
|
[
|
||
|
[
|
||
|
'fields' => [
|
||
|
'Database type' => 'MySQL',
|
||
|
'Database host'=> 'localhost'
|
||
|
]
|
||
|
]
|
||
|
],
|
||
|
// TLS is available when host name starts with a slash - MySQL.
|
||
|
[
|
||
|
[
|
||
|
'fields' => [
|
||
|
'Database type' => 'MySQL',
|
||
|
'Database host'=> '/123'
|
||
|
],
|
||
|
'tls_displayed' => true
|
||
|
]
|
||
|
],
|
||
|
// TLS available when IP address is used as host name - PostgreSQL.
|
||
|
[
|
||
|
[
|
||
|
'fields' => [
|
||
|
'Database type' => 'PostgreSQL',
|
||
|
'Database host'=> '127.0.0.1'
|
||
|
],
|
||
|
'tls_displayed' => true
|
||
|
]
|
||
|
],
|
||
|
// TLS available when string is used as host name - PostgreSQL.
|
||
|
[
|
||
|
[
|
||
|
'fields' => [
|
||
|
'Database type' => 'PostgreSQL',
|
||
|
'Database host'=> 'abc'
|
||
|
],
|
||
|
'tls_displayed' => true
|
||
|
]
|
||
|
],
|
||
|
// TLS available when empty space is used as host name - PostgreSQL.
|
||
|
[
|
||
|
[
|
||
|
'fields' => [
|
||
|
'Database type' => 'PostgreSQL',
|
||
|
'Database host'=> ' '
|
||
|
],
|
||
|
'tls_displayed' => true
|
||
|
]
|
||
|
],
|
||
|
// TLS NOT available when host name is empty - PostgreSQL.
|
||
|
[
|
||
|
[
|
||
|
'fields' => [
|
||
|
'Database type' => 'PostgreSQL',
|
||
|
'Database host'=> ''
|
||
|
]
|
||
|
]
|
||
|
],
|
||
|
// TLS is available when host name is equal to "localhost" - PostgreSQL.
|
||
|
[
|
||
|
[
|
||
|
'fields' => [
|
||
|
'Database type' => 'PostgreSQL',
|
||
|
'Database host'=> 'localhost'
|
||
|
],
|
||
|
'tls_displayed' => true
|
||
|
]
|
||
|
],
|
||
|
// TLS NOT available when host name starts with a slash - PostgreSQL.
|
||
|
[
|
||
|
[
|
||
|
'fields' => [
|
||
|
'Database type' => 'PostgreSQL',
|
||
|
'Database host'=> '/123'
|
||
|
]
|
||
|
]
|
||
|
]
|
||
|
];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @dataProvider getDbConnectionDetailsForTls
|
||
|
*/
|
||
|
public function testFormSetup_tlsParameterPresence($data) {
|
||
|
// Open "Configure DB connection" section.
|
||
|
$this->openSpecifiedSection('Configure DB connection');
|
||
|
$form = $this->query('xpath://form')->asForm()->one();
|
||
|
$database_types = $form->getField('Database type')->getOptions()->asText();
|
||
|
|
||
|
// Skip data provider if the defined DB type is not available on the current machine.
|
||
|
if (!in_array($data['fields']['Database type'], $database_types)) {
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
// Fill DB parameters and check if TLS parameters are displayed.
|
||
|
$form->fill($data['fields']);
|
||
|
$form->invalidate();
|
||
|
$this->page->removeFocus();
|
||
|
if (CTestArrayHelper::get($data, 'tls_displayed', false)) {
|
||
|
$form->getField('Database TLS encryption')->check();
|
||
|
$form->query('xpath:.//label[@for="verify_certificate"]/span')->asCheckbox()->one()->check();
|
||
|
$tls_fields = [
|
||
|
'Database TLS CA file',
|
||
|
'Database TLS key file',
|
||
|
'Database TLS certificate file'
|
||
|
];
|
||
|
foreach ($tls_fields as $tls_field) {
|
||
|
$this->assertTrue($form->getField($tls_field)->isDisplayed());
|
||
|
}
|
||
|
$verify_host_field = $form->query('id:verify_host')->asCheckbox()->one();
|
||
|
if ($data['fields']['Database type'] === 'MySQL') {
|
||
|
$this->assertTrue($form->getField('Database TLS cipher list')->isDisplayed());
|
||
|
$this->assertFalse($verify_host_field->isEnabled());
|
||
|
}
|
||
|
else {
|
||
|
$this->assertFalse($this->query('xpath://span[text()="Database TLS cipher list"]')->one(false)->isValid());
|
||
|
$this->assertTrue($verify_host_field->isEnabled());
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
$tls_text = 'Connection will not be encrypted because it uses a socket file (on Unix) or shared memory (Windows).';
|
||
|
$this->assertEquals($tls_text, $form->query('id:tls_encryption_hint')->one()->getText());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function testFormSetup_backButtons() {
|
||
|
// Open the Pre-installation summary section.
|
||
|
$this->openSpecifiedSection('Pre-installation summary');
|
||
|
|
||
|
// Proceed back to the 1st section of the setup form.
|
||
|
$this->query('button:Back')->one()->click();
|
||
|
$this->assertEquals('Settings', $this->query('xpath://h1')->one()->getText());
|
||
|
$this->query('button:Back')->one()->click();
|
||
|
$this->assertEquals('Configure DB connection', $this->query('xpath://h1')->one()->getText());
|
||
|
$this->query('button:Back')->one()->click();
|
||
|
$this->assertEquals('Check of pre-requisites', $this->query('xpath://h1')->one()->getText());
|
||
|
$this->query('button:Back')->one()->click();
|
||
|
$this->assertEquals("Welcome to\nZabbix ".ZABBIX_EXPORT_VERSION, $this->query('xpath://div[@class="setup-title"]')->one()->getText());
|
||
|
$this->checkSections('Welcome');
|
||
|
$this->checkButtons('first section');
|
||
|
|
||
|
// Cancel setup form update.
|
||
|
$this->query('button:Cancel')->one()->click();
|
||
|
$this->assertStringContainsString('zabbix.php?action=dashboard.view', $this->page->getCurrentURL());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function checks the title of the current section, section navigation column and presence of text if defined.
|
||
|
*
|
||
|
* @param string $title title of the current setup form section
|
||
|
* @param string $text text that should be present in a paragraph of the current setup form section
|
||
|
*/
|
||
|
private function checkPageTextElements($title, $text = null) {
|
||
|
$this->assertTrue($this->query('xpath://h1[text()='.CXPathHelper::escapeQuotes($title).']')->one()->isValid());
|
||
|
$this->checkSections($title);
|
||
|
if ($text) {
|
||
|
$this->assertStringContainsString($text, $this->query('xpath:.//p')->one()->getText());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function checks if the buttons on the currently opened setup form section are clickable.
|
||
|
*
|
||
|
* @param string $section position of current section in the form (first, last, middle)
|
||
|
*/
|
||
|
private function checkButtons($section = 'middle section') {
|
||
|
switch ($section) {
|
||
|
case 'first section':
|
||
|
$buttons = [
|
||
|
'Cancel' => true,
|
||
|
'Back' => false,
|
||
|
'Next step' => true
|
||
|
];
|
||
|
break;
|
||
|
|
||
|
case 'last section':
|
||
|
$buttons = [
|
||
|
'Cancel' => false,
|
||
|
'Back' => false,
|
||
|
'Finish' => true
|
||
|
];
|
||
|
break;
|
||
|
|
||
|
case 'middle section':
|
||
|
$buttons = [
|
||
|
'Cancel' => true,
|
||
|
'Back' => true,
|
||
|
'Next step' => true
|
||
|
];
|
||
|
break;
|
||
|
|
||
|
case 'russian':
|
||
|
$buttons = [
|
||
|
'Отмена' => true,
|
||
|
'Назад' => false,
|
||
|
'Далее' => true
|
||
|
];
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
foreach ($buttons as $button => $clickable) {
|
||
|
$this->assertEquals($clickable, $this->query('button', $button)->one()->isCLickable());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function checks that all sections are present in the section navigation column, and that the current (or all
|
||
|
* section) are grayed out.
|
||
|
*
|
||
|
* @param string $current title of the current setup form section.
|
||
|
*/
|
||
|
private function checkSections($current) {
|
||
|
$sections = [
|
||
|
'Welcome',
|
||
|
'Check of pre-requisites',
|
||
|
'Configure DB connection',
|
||
|
'Settings',
|
||
|
'Pre-installation summary',
|
||
|
'Install'
|
||
|
];
|
||
|
|
||
|
foreach ($sections as $section_name) {
|
||
|
$section = $this->query('xpath://li[text()='.CXPathHelper::escapeQuotes($section_name).']')->one();
|
||
|
$this->assertTrue($section->isValid());
|
||
|
// It is required to check that all sections are grayed out because Install is the last step.
|
||
|
if ($section_name === $current || $current === 'Install') {
|
||
|
$this->assertEquals('setup-left-current', $section->getAttribute('class'));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function opens the setup form and navigates to the specified section.
|
||
|
*
|
||
|
* @param string $section the name of the section to be opened
|
||
|
*/
|
||
|
private function openSpecifiedSection($section) {
|
||
|
$this->page->login()->open('setup.php')->waitUntilReady();
|
||
|
$this->query('button:Next step')->one()->click();
|
||
|
$this->query('button:Next step')->one()->click();
|
||
|
// No actions required in case of Configure DB connection section.
|
||
|
if ($section === 'Configure DB connection') {
|
||
|
return;
|
||
|
}
|
||
|
// Define the number of clicks on the Next step button depending on the name of the desired section.
|
||
|
$skip_sections = [
|
||
|
'Settings' => 1,
|
||
|
'Pre-installation summary' => 2,
|
||
|
'Install' => 3
|
||
|
];
|
||
|
// Fill in DB parameters and navigate to the desired section.
|
||
|
$db_parameters = $this->getDbParameters();
|
||
|
$form = $this->query('xpath://form')->asForm()->one();
|
||
|
$form->fill($db_parameters);
|
||
|
|
||
|
for ($i = 0; $i < $skip_sections[$section]; $i++) {
|
||
|
$this->query('button:Next step')->one()->click();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function retrieves the values to be filled in the Configure DB connection section.
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
private function getDbParameters() {
|
||
|
global $DB;
|
||
|
$db_parameters = [
|
||
|
'Database host' => $DB['SERVER'],
|
||
|
'Database name' => $DB['DATABASE'],
|
||
|
'Database port' => $DB['PORT'],
|
||
|
'User' => $DB['USER'],
|
||
|
'Password' => $DB['PASSWORD']
|
||
|
];
|
||
|
$db_parameters['Database type'] = ($DB['TYPE'] === ZBX_DB_POSTGRESQL) ? 'PostgreSQL' : 'MySQL';
|
||
|
|
||
|
return $db_parameters;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function checks the layout of the TLS encryption fields
|
||
|
*/
|
||
|
private function checkTlsFieldsLayout() {
|
||
|
$form = $this->query('xpath://form')->asForm()->one();
|
||
|
$tls_encryption = $form->getField('Database TLS encryption');
|
||
|
$this->assertTrue($tls_encryption->isChecked());
|
||
|
|
||
|
// Check that Verify database certificate field is visible and set it.
|
||
|
$verify_certificate = $form->query('xpath:.//label[@for="verify_certificate"]/span')->asCheckbox()->one();
|
||
|
$this->assertTrue($verify_certificate->isDisplayed());
|
||
|
$verify_certificate->check();
|
||
|
|
||
|
$form->invalidate();
|
||
|
$tls_fields = [
|
||
|
'Database TLS CA file',
|
||
|
'Database TLS key file',
|
||
|
'Database TLS certificate file'
|
||
|
];
|
||
|
foreach ($tls_fields as $tls_field_name) {
|
||
|
$tls_field = $form->getField($tls_field_name);
|
||
|
$this->assertTrue($tls_field->isDisplayed());
|
||
|
$this->assertEquals(255, $tls_field->getAttribute('maxlength'));
|
||
|
}
|
||
|
// Check that Database host verification field is displayed.
|
||
|
$this->assertTrue($form->query('xpath:.//label[@for="verify_host"]/span')->one()->isDisplayed());
|
||
|
// Uncheck the Database TLS encryption and verify that Verify database certificate field is hidden.
|
||
|
$tls_encryption->uncheck();
|
||
|
$this->assertFalse($verify_certificate->isDisplayed());
|
||
|
}
|
||
|
}
|