<?php
/*
** Copyright (C) 2001-2025 Zabbix SIA
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see <https://www.gnu.org/licenses/>.
**/

require_once dirname(__FILE__).'/../include/CIntegrationTest.php';

/**
 * Test suite for action notifications
 *
 * @required-components server
 * @configurationDataProvider defaultConfigurationProvider
 * @backup items,hosts,proxy,history_text
 * @hosts test_actions
 */
class testItemTimeouts extends CIntegrationTest {

	const HOSTNAME_AGENT = "agent_host_timeouts";
	const HOSTNAME_AGENT2 = "agent2_host_timeouts";
	const HOSTNAME_SNMP = "snmp_host_timeouts";
	const HOSTNAME_SSH = "ssh_host_timeouts";
	const HOSTNAME_SIMPLE = "simple_host_timeouts";

	private static $hostids;
	private static $itemids;

	/**
	 * @inheritdoc
	 */
	public function prepareData() {
		// Create host "test_host"
		$response = $this->call('host.create', [
			[
				'host' => self::HOSTNAME_AGENT,
				'interfaces' => [
					'type' => 1,
					'main' => 1,
					'useip' => 1,
					'ip' => '127.0.0.1',
					'dns' => '',
					'port' => $this->getConfigurationValue(self::COMPONENT_AGENT, 'ListenPort')
				],
				'groups' => [['groupid' => 4]],
				'status' => HOST_STATUS_MONITORED
			],
			[
				'host' => self::HOSTNAME_AGENT2,
				'interfaces' => [
					'type' => 1,
					'main' => 1,
					'useip' => 1,
					'ip' => '127.0.0.1',
					'dns' => '',
					'port' => $this->getConfigurationValue(self::COMPONENT_AGENT2, 'ListenPort')
				],
				'groups' => [['groupid' => 4]],
				'status' => HOST_STATUS_MONITORED
			]
		]);

		$this->assertArrayHasKey('hostids', $response['result']);
		$this->assertArrayHasKey(0, $response['result']['hostids']);

		self::$hostids[self::HOSTNAME_AGENT] = $response['result']['hostids'][0];
		self::$hostids[self::HOSTNAME_AGENT2] = $response['result']['hostids'][1];

		// Get host interface ids.
		$response = $this->call('host.get', [
			'output' => ['host'],
			'hostids' => [
				self::$hostids[self::HOSTNAME_AGENT],
				self::$hostids[self::HOSTNAME_AGENT2]
			],
			'selectInterfaces' => ['interfaceid'],
			'sortfield' => 'hostid'
		]);
		$this->assertArrayHasKey(0, $response['result']);
		$this->assertArrayHasKey('interfaces', $response['result'][0]);
		$this->assertTrue(count($response['result']) == 2);
		$agent_interfaceid = $response['result'][0]['interfaces'][0]['interfaceid'];
		$agent2_interfaceid = $response['result'][1]['interfaces'][0]['interfaceid'];

		$response = $this->call('host.create', [
			[
				'host' => self::HOSTNAME_SSH,
				'interfaces' => [],
				'groups' => [['groupid' => 4]],
				'status' => HOST_STATUS_NOT_MONITORED
			]
		]);
		$this->assertArrayHasKey('hostids', $response['result']);
		$this->assertArrayHasKey(0, $response['result']['hostids']);
		self::$hostids[self::HOSTNAME_SSH] = $response['result']['hostids'][0];

		$response = $this->call('host.create', [
			[
				'host' => self::HOSTNAME_SNMP,
				'interfaces' => [
					'type' => INTERFACE_TYPE_SNMP,
					'main' => 1,
					'useip' => 1,
					'ip' => '127.0.0.1',
					'dns' => '',
					'port' => '10987',
					'details' => [
						'version' => 3,
						'bulk' => 0,
						'securityname' => '',
						'contextname' => '',
						'securitylevel' => 0
					]
				],
				'groups' => [['groupid' => 4]],
				'status' => HOST_STATUS_NOT_MONITORED
			]
		]);
		$this->assertArrayHasKey('hostids', $response['result']);
		$this->assertArrayHasKey(0, $response['result']['hostids']);
		self::$hostids[self::HOSTNAME_SNMP] = $response['result']['hostids'][0];

		$response = $this->call('host.create', [
			[
				'host' => self::HOSTNAME_SIMPLE,
				'interfaces' => [],
				'groups' => [['groupid' => 4]],
				'status' => HOST_STATUS_NOT_MONITORED
			]
		]);
		$this->assertArrayHasKey('hostids', $response['result']);
		$this->assertArrayHasKey(0, $response['result']['hostids']);
		self::$hostids[self::HOSTNAME_SIMPLE] = $response['result']['hostids'][0];

		// Get host interface ids.
		$response = $this->call('host.get', [
			'output' => ['host'],
			'hostids' => self::$hostids[self::HOSTNAME_SNMP],
			'selectInterfaces' => ['interfaceid']
		]);

		$this->assertArrayHasKey(0, $response['result']);
		$this->assertArrayHasKey('interfaces', $response['result'][0]);
		$this->assertArrayHasKey(0, $response['result'][0]['interfaces']);
		$snmp_interfaceid = $response['result'][0]['interfaces'][0]['interfaceid'];

		$items = [
			[
				'hostid' => self::$hostids[self::HOSTNAME_AGENT],
				'name' => "userparam.test",
				'key_' => 'userparam.test',
				'interfaceid' => $agent_interfaceid,
				'type' => ITEM_TYPE_ZABBIX,
				'value_type' => ITEM_VALUE_TYPE_TEXT,
				'delay' => '1m',
				'timeout' => '10s'
			],
			[
				'hostid' => self::$hostids[self::HOSTNAME_AGENT2],
				'name' => "userparam.test",
				'key_' => 'userparam.test',
				'interfaceid' => $agent2_interfaceid,
				'type' => ITEM_TYPE_ZABBIX,
				'value_type' => ITEM_VALUE_TYPE_TEXT,
				'delay' => '1m',
				'timeout' => '10s'
			],
			[
				'hostid' => self::$hostids[self::HOSTNAME_AGENT],
				'name' => "system.run",
				'key_' => 'system.run[sleep 5 && echo ok]',
				'interfaceid' => $agent_interfaceid,
				'type' => ITEM_TYPE_ZABBIX,
				'value_type' => ITEM_VALUE_TYPE_TEXT,
				'delay' => '1m',
				'timeout' => '10s'
			],
			[
				'hostid' => self::$hostids[self::HOSTNAME_AGENT2],
				'name' => "system.run",
				'key_' => 'system.run[sleep 5 && echo ok]',
				'interfaceid' => $agent2_interfaceid,
				'type' => ITEM_TYPE_ZABBIX,
				'value_type' => ITEM_VALUE_TYPE_TEXT,
				'delay' => '1m',
				'timeout' => '10s'
			],
			[
				'hostid' => self::$hostids[self::HOSTNAME_AGENT],
				'name' => "userparam.test.active",
				'key_' => 'userparam.test.active',
				'interfaceid' => $agent_interfaceid,
				'type' => ITEM_TYPE_ZABBIX,
				'value_type' => ITEM_VALUE_TYPE_TEXT,
				'delay' => '1m',
				'timeout' => '10s'
			],
			[
				'hostid' => self::$hostids[self::HOSTNAME_AGENT2],
				'name' => "userparam.test.active",
				'key_' => 'userparam.test.active',
				'interfaceid' => $agent2_interfaceid,
				'type' => ITEM_TYPE_ZABBIX,
				'value_type' => ITEM_VALUE_TYPE_TEXT,
				'delay' => '1m',
				'timeout' => '10s'
			],
			[
				'hostid' => self::$hostids[self::HOSTNAME_AGENT],
				'name' => "test_external.sh",
				'key_' => 'test_external.sh',
				'interfaceid' => $agent_interfaceid,
				'type' => ITEM_TYPE_EXTERNAL,
				'value_type' => ITEM_VALUE_TYPE_TEXT,
				'delay' => '1m',
				'timeout' => '10s'
			],
			[
				'hostid' => self::$hostids[self::HOSTNAME_SNMP],
				'name' => "snmp",
				'key_' => 'snmp',
				'snmp_oid' => 'walk[1.3.6.1.1]',
				'interfaceid' => $snmp_interfaceid,
				'type' => ITEM_TYPE_SNMP,
				'value_type' => ITEM_VALUE_TYPE_TEXT,
				'delay' => '10s',
				'timeout' => '6s'
			],
			[
				'hostid' => self::$hostids[self::HOSTNAME_SSH],
				'name' => "ssh",
				'key_' => 'ssh.run[test,192.168.9.25,822]',
				'authtype' => 0,
				'password' => 'user12345',
				'username' => 'user12345',
				'params' => 'echo ok',
				'type' => ITEM_TYPE_SSH,
				'value_type' => ITEM_VALUE_TYPE_TEXT,
				'delay' => '10s',
				'timeout' => '6s'
			],
			[
				'hostid' => self::$hostids[self::HOSTNAME_SIMPLE],
				'name' => "simple",
				'key_' => 'net.tcp.service[http,192.168.9.25,1]',
				'type' => ITEM_TYPE_SIMPLE,
				'value_type' => ITEM_VALUE_TYPE_TEXT,
				'delay' => '10s',
				'timeout' => '6s'
			]
		];

		foreach ($items as $item) {
			$response = $this->call('item.create', $item);
			$this->assertArrayHasKey('itemids', $response['result']);
			$this->assertEquals(1, count($response['result']['itemids']));
			self::$itemids[$item['name']] = $response['result']['itemids'][0];
		}

		$external_script_data = <<<HEREDOC
		#!/bin/bash
		sleep 6
		echo ok
		HEREDOC;

		$this->assertTrue(@file_put_contents('/tmp/test_external.sh', $external_script_data) !== false); // TODO: const
		$this->assertTrue(@chmod('/tmp/test_external.sh', 0755) !== false); // TODO: const

		return true;
	}

	public function proxyConfigurationProvider() {
		return [
			self::COMPONENT_SERVER => [
				'DebugLevel' => 5,
				'LogFileSize' => 0
			],
			self::COMPONENT_PROXY => [
				'DebugLevel' => 5,
				'LogFileSize' => 0,
				'Hostname' => 'Proxy',
				'ProxyMode' => 1
			]
		];
	}

	public function defaultConfigurationProvider() {
		return [
			self::COMPONENT_SERVER => [
				'DebugLevel' => 4,
				'LogFileSize' => 20,
				'ExternalScripts' => '/tmp'
			],
			self::COMPONENT_AGENT => [
				'Hostname' => self::HOSTNAME_AGENT,
				'ServerActive' => '127.0.0.1:'.self::getConfigurationValue(self::COMPONENT_SERVER,
						'ListenPort', 10051),
				'AllowKey' => 'system.run[*]',
				'LogRemoteCommands' => 1,
				'UnsafeUserParameters' => 1,
				'UserParameter' => [
					'userparam.test,sleep 5 && echo ok',
					'userparam.test.active,sleep 5 && echo ok'
				]
			],
			self::COMPONENT_AGENT2 => [
				'Hostname' => self::HOSTNAME_AGENT2,
				'ServerActive' => '127.0.0.1:'.self::getConfigurationValue(self::COMPONENT_SERVER,
						'ListenPort', 10051),
				'AllowKey' => 'system.run[*]',
				'UnsafeUserParameters' => 1,
				'UserParameter' => [
					'userparam.test,sleep 5 && echo ok',
					'userparam.test.active,sleep 5 && echo ok'
				]
			]
		];
	}

	public function serverConfigurationProviderTrace() {
		return [
			self::COMPONENT_SERVER => [
				'DebugLevel' => 5,
				'LogFileSize' => 0,
				'Timeout' => 30
			]
		];
	}

	private function extractSyncedTimeouts($initial_timeouts, $component) {
		$log = file_get_contents(self::getLogPath($component));
		$data = explode("\n", $log);
		$sync = preg_grep('/item timeouts:/', $data);
		$this->assertTrue(count($sync) > 0);

		/* We cannot just take $lines_expected number of lines after 'item timeouts' in log. */
		/* Another process may start writing into log here. So, we must filter lines by pid. */
		$pid = strtok(array_values($sync)[0], ':');
		$sync_idx = array_keys($sync)[0];
		$lines_expected = count($initial_timeouts);

		$synced_timeouts = array();
		for ($x = $sync_idx + 1; $x < count($data); $x++) {
			if (count($synced_timeouts) == $lines_expected) {
				break;
			}
			if (preg_match('/^'.$pid.'/', $data[$x])) {
				array_push($synced_timeouts, $data[$x]);
			}
		}

		$synced_timeouts2 = preg_replace("/^\s*[0-9]+:[0-9]+:[0-9]+\.[0-9]+\s+/", "", $synced_timeouts);

		$pairs = [];
		foreach ($synced_timeouts2 as $v) {
			$p = explode(":", $v);
			$name = $p[0];
			$value = $p[1];
			$pairs["timeout_" . $name] = $value;
		}

		return $pairs;
	}

	/**
	 * Test if both active and passive agent checks are processed.
	 *
	 * @required-components server
	 * @configurationDataProvider serverConfigurationProviderTrace
	 * @backup config
	 */
	public function testItemTimeouts_checkConfigSync() {
		self::stopComponent(self::COMPONENT_SERVER);

		$this->clearLog(self::COMPONENT_SERVER);

		$initial_timeouts = [
			'timeout_zabbix_agent' => '4s',
			'timeout_simple_check' => '5s',
			'timeout_snmp_agent' => '6s',
			'timeout_external_check' => '7s',
			'timeout_db_monitor' => '8s',
			'timeout_http_agent' => '9s',
			'timeout_ssh_agent' => '10s',
			'timeout_telnet_agent' => '11s',
			'timeout_script' => '12s'
		];

		$response = $this->call('settings.update', $initial_timeouts);
		$this->assertEquals(count($initial_timeouts), count($response['result']));

		self::startComponent(self::COMPONENT_SERVER);

		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "End of DCdump_config()", true, 30, 1);

		$synced_timeouts = $this->extractSyncedTimeouts($initial_timeouts, self::COMPONENT_SERVER);
		$this->assertEqualsCanonicalizing($synced_timeouts, $initial_timeouts);

		$updated_timeouts = [
			'timeout_zabbix_agent' => '1m',
			'timeout_simple_check' => '1m',
			'timeout_snmp_agent' => '1m',
			'timeout_external_check' => '1m',
			'timeout_db_monitor' => '1m',
			'timeout_http_agent' => '1m',
			'timeout_ssh_agent' => '2m',
			'timeout_telnet_agent' => '2m',
			'timeout_script' => '2m'
		];

		$this->reloadConfigurationCache(self::COMPONENT_SERVER);

		$response = $this->call('settings.update', $updated_timeouts);
		$this->assertEquals(count($updated_timeouts), count($response['result']));

		$this->clearLog(self::COMPONENT_SERVER);

		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "End of DCdump_config()", true, 30, 1);

		$synced_timeouts = $this->extractSyncedTimeouts($updated_timeouts, self::COMPONENT_SERVER);
		$this->assertEqualsCanonicalizing($synced_timeouts, $updated_timeouts);

		return true;
	}

	/**
	 * Test timeouts for various agent checks and external check.
	 *
	 * @required-components server, agent, agent2
	 * @configurationDataProvider defaultConfigurationProvider
	 * @backup config, history_text, items, item_rtdata
	 */
	public function testItemTimeouts_checkTimeouts() {
		$this->reloadConfigurationCache(self::COMPONENT_SERVER);
		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "End of zbx_dc_sync_configuration()", true, 30, 1);

		foreach (self::$itemids as $name => $id) {
			if (in_array($name, ['userparam.test.active', 'snmp', 'ssh', 'simple']))
				continue;

			$response = $this->call('task.create', [
				'type' => ZBX_TM_TASK_CHECK_NOW,
				'request' => [
					'itemid' => $id
				]
			]);
		}

		foreach (self::$itemids as $name => $id) {
			if (in_array($name, ['snmp', 'ssh', 'simple']))
				continue;

			$response = $this->callUntilDataIsPresent('history.get', [
				'output' => ['value'],
				'itemids' => [$id],
				'history' => ITEM_VALUE_TYPE_TEXT,
				'sortorder' => 'DESC',
				'sortfield' => 'clock',
				'limit' => 1
			], 30, 2);
		}

		return true;
	}

	/**
	 * Test timeout for SNMP check.
	 *
	 * @required-components server
	 * @configurationDataProvider defaultConfigurationProvider
	 * @backup config, hosts, items, item_rtdata
	 */
	public function testItemTimeouts_checkSnmp() {
		self::stopComponent(self::COMPONENT_SERVER);
		$response = $this->call('host.update', [
			'hostid' => self::$hostids[self::HOSTNAME_SNMP],
			'status' => HOST_STATUS_MONITORED
		]);
		$this->assertArrayHasKey('hostids', $response['result']);
		$this->assertEquals(1, count($response['result']['hostids']));

		self::startComponent(self::COMPONENT_SERVER);
		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "End of zbx_dc_sync_configuration()", true, 30, 1);
		$this->clearLog(self::COMPONENT_SERVER);

		$response = $this->call('task.create', [
			'type' => ZBX_TM_TASK_CHECK_NOW,
			'request' => [
				'itemid' => self::$itemids['snmp']
			]
		]);

		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "In zbx_async_check_snmp", true, 90, 1, true);
		$tm1 = time();
		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "End of process_async_result", true, 90, 1, true);
		$tm2 = time();
		$this->assertTrue($tm2 - $tm1 <= 7 * 2);
	}

	/**
	 * Test timeout for SSH check.
	 *
	 * @required-components server
	 * @configurationDataProvider defaultConfigurationProvider
	 * @backup config, hosts, items, item_rtdata
	 */
	public function testItemTimeouts_checkSsh() {
		self::stopComponent(self::COMPONENT_SERVER);

		$response = $this->call('host.update', [
			'hostid' => self::$hostids[self::HOSTNAME_SSH],
			'status' => HOST_STATUS_MONITORED
		]);
		$this->assertArrayHasKey('hostids', $response['result']);
		$this->assertEquals(1, count($response['result']['hostids']));

		self::startComponent(self::COMPONENT_SERVER);
		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "End of zbx_dc_sync_configuration()", true, 30, 1);
		$this->clearLog(self::COMPONENT_SERVER);

		$response = $this->call('task.create', [
			'type' => ZBX_TM_TASK_CHECK_NOW,
			'request' => [
				'itemid' => self::$itemids['ssh']
			]
		]);

		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "In ssh_run()", true, 90, 1, true);
		$tm1 = time();
		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "End of ssh_run().*NOTSUPPORTED", true, 90, 1, true);
		$tm2 = time();
		$this->assertTrue($tm2 - $tm1 <= 7);

		return true;
	}

	/**
	 * Test timeout for simple check.
	 *
	 * @required-components server
	 * @configurationDataProvider defaultConfigurationProvider
	 * @backup config, hosts, items, item_rtdata
	 */
	public function testItemTimeouts_checkSimple() {
		$response = $this->call('host.update', [
			'hostid' => self::$hostids[self::HOSTNAME_SIMPLE],
			'status' => HOST_STATUS_MONITORED
		]);
		$this->assertArrayHasKey('hostids', $response['result']);
		$this->assertEquals(1, count($response['result']['hostids']));
		$this->clearLog(self::COMPONENT_SERVER);

		$this->reloadConfigurationCache(self::COMPONENT_SERVER);
		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "End of zbx_dc_sync_configuration()", true, 30, 1);
		$this->clearLog(self::COMPONENT_SERVER);

		$response = $this->call('task.create', [
			'type' => ZBX_TM_TASK_CHECK_NOW,
			'request' => [
				'itemid' => self::$itemids['simple']
			]
		]);

		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "In get_value_simple()", true, 90, 1, true);
		$tm1 = time();
		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "End of get_value_simple()", true, 90, 1, true);
		$tm2 = time();
		$this->assertTrue($tm2 - $tm1 <= 7);

		return true;
	}

	/**
	 * Test if proxy receives per-proxy timeout sets from server.
	 *
	 * @required-components server, proxy
	 * @configurationDataProvider proxyConfigurationProvider
	 */
	public function testItemTimeouts_checkProxyconfig() {
		$proxy_timeouts = [
			'timeout_zabbix_agent' => '4s',
			'timeout_simple_check' => '5s',
			'timeout_snmp_agent' => '6s',
			'timeout_external_check' => '7s',
			'timeout_db_monitor' => '8s',
			'timeout_http_agent' => '9s',
			'timeout_ssh_agent' => '10s',
			'timeout_telnet_agent' => '11s',
			'timeout_script' => '12s',
			'timeout_browser' => '13s'
		];

		$request = [
			'name' => 'Proxy',
			'operating_mode' => PROXY_OPERATING_MODE_PASSIVE,
			'hosts' => [],
			'address' => '127.0.0.1',
			'port' => PHPUNIT_PORT_PREFIX.self::PROXY_PORT_SUFFIX,
			'custom_timeouts' => 1
		];

		$response = $this->call('proxy.create', array_merge($request, $proxy_timeouts));
		$this->assertArrayHasKey("proxyids", $response['result']);
		$this->assertArrayHasKey('0', $response['result']['proxyids']);
		$proxyid = $response['result']['proxyids'][0];

		$this->reloadConfigurationCache(self::COMPONENT_SERVER);
		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "End of zbx_dc_sync_configuration()", true, 30, 1);
		$this->clearLog(self::COMPONENT_PROXY);
		$this->clearLog(self::COMPONENT_SERVER);

		$this->reloadConfigurationCache(self::COMPONENT_PROXY);
		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'sending configuration data to proxy "Proxy"', true, 90, 1);
		$this->waitForLogLineToBePresent(self::COMPONENT_PROXY, "received configuration data from server", true, 90, 1);
		$this->waitForLogLineToBePresent(self::COMPONENT_PROXY, "End of DCdump_config()", true, 30, 1);

		$synced_timeouts = $this->extractSyncedTimeouts($proxy_timeouts, self::COMPONENT_PROXY);
		$this->assertEqualsCanonicalizing($synced_timeouts, $proxy_timeouts);

		$updated_timeouts = [
			'timeout_zabbix_agent' => '1m',
			'timeout_simple_check' => '1m',
			'timeout_snmp_agent' => '1m',
			'timeout_external_check' => '1m',
			'timeout_db_monitor' => '1m',
			'timeout_http_agent' => '1m',
			'timeout_ssh_agent' => '2m',
			'timeout_telnet_agent' => '2m',
			'timeout_script' => '2m'
		];

		$response = $this->call('proxy.update', array_merge(["proxyid" => $proxyid], $updated_timeouts));
		$this->assertArrayHasKey("proxyids", $response['result']);

		$this->clearLog(self::COMPONENT_SERVER);
		$this->reloadConfigurationCache(self::COMPONENT_SERVER);
		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, "End of zbx_dc_sync_configuration()", true, 30, 1);
		$this->clearLog(self::COMPONENT_PROXY);
		$this->clearLog(self::COMPONENT_SERVER);

		$this->reloadConfigurationCache(self::COMPONENT_PROXY);
		$this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'sending configuration data to proxy "Proxy"', true, 90, 1);
		$this->waitForLogLineToBePresent(self::COMPONENT_PROXY, "received configuration data from server", true, 90, 1);
		$this->waitForLogLineToBePresent(self::COMPONENT_PROXY, "End of DCdump_config()", true, 30, 1);

		$synced_timeouts2 = $this->extractSyncedTimeouts($updated_timeouts, self::COMPONENT_PROXY);

		$this->assertEqualsCanonicalizing($synced_timeouts2, $updated_timeouts);

		return true;
	}
}