call('host.create', [ [ 'host' => self::HOSTNAME1, 'interfaces' => [], 'groups' => [['groupid' => 4]], 'status' => HOST_STATUS_MONITORED ] ]); $this->assertArrayHasKey('hostids', $response['result']); $this->assertArrayHasKey(0, $response['result']['hostids']); self::$hostid_normal = $response['result']['hostids'][0]; // Create host "test_history_push_non_monitored" $response = $this->call('host.create', [ [ 'host' => "test_history_push_non_monitored", 'interfaces' => [], 'groups' => [['groupid' => 4]], 'status' => HOST_STATUS_NOT_MONITORED ] ]); $this->assertArrayHasKey('hostids', $response['result']); $this->assertArrayHasKey(0, $response['result']['hostids']); self::$hostid_non_monitored = $response['result']['hostids'][0]; // Create host "test_history_push_maintained" $response = $this->call('host.create', [ [ 'host' => "test_history_push_maintained", 'interfaces' => [], 'groups' => [['groupid' => 4]], 'status' => HOST_STATUS_MONITORED ] ]); $this->assertArrayHasKey('hostids', $response['result']); $this->assertArrayHasKey(0, $response['result']['hostids']); self::$hostid_maintained = $response['result']['hostids'][0]; // Create items $items = [ [ 'key_' => 'calc_item', 'type' => ITEM_TYPE_CALCULATED, 'params' => '1', 'value_type' => ITEM_VALUE_TYPE_UINT64, 'delay' => '3s' ], [ 'key_' => 'trapper_uint', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_UINT64 ], [ 'key_' => 'trapper_uint2', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_UINT64 ], [ 'key_' => 'trapper_uint_host_key_test', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_UINT64 ], [ 'key_' => 'trapper_uint_no_perms', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_UINT64 ], [ 'key_' => 'trapper_uint_bad_valuetype', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_UINT64 ], [ 'key_' => 'trapper_uint_disabled', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_UINT64, 'status' => ITEM_STATUS_DISABLED ], [ 'key_' => 'trapper_float', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_FLOAT ], [ 'key_' => 'trapper_log', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_LOG ], [ 'key_' => 'trapper_text', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_TEXT ], [ 'key_' => 'trapper_str', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_STR ], [ 'key_' => 'trapper_text_bad_allow_hosts', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_TEXT, 'trapper_hosts' => 'non.existent.host' ], [ 'key_' => 'http_agent_text', 'type' => ITEM_TYPE_HTTPAGENT, 'value_type' => ITEM_VALUE_TYPE_TEXT, 'url' => 'http://127.0.0.1/test', 'delay' => '10s', 'allow_traps' => 1 ], [ 'key_' => 'http_agent_text_no_trap', 'type' => ITEM_TYPE_HTTPAGENT, 'value_type' => ITEM_VALUE_TYPE_TEXT, 'url' => 'http://127.0.0.1/test', 'delay' => '10s', 'allow_traps' => 0 ] ]; foreach ($items as $item) { $item['name'] = $item['key_']; $item['hostid'] = self::$hostid_normal; $response = $this->call('item.create', $item); $this->assertArrayHasKey('itemids', $response['result']); $this->assertEquals(1, count($response['result']['itemids'])); $itemid = $response['result']['itemids'][0]; self::$itemids[$item['key_']] = $itemid; } $items_nonavail_hosts = [ [ 'key_' => 'trapper_uint_non_monitored_host', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_UINT64, 'hostid' => self::$hostid_non_monitored ], [ 'key_' => 'trapper_uint_maintained_host', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_UINT64, 'hostid' => self::$hostid_maintained ], [ 'key_' => 'trapper_uint_no_perms_host', 'type' => ITEM_TYPE_TRAPPER, 'value_type' => ITEM_VALUE_TYPE_UINT64, 'hostid' => self::$hostid_normal ] ]; foreach ($items_nonavail_hosts as $item) { $item['name'] = $item['key_']; $response = $this->call('item.create', $item); $this->assertArrayHasKey('itemids', $response['result']); $this->assertEquals(1, count($response['result']['itemids'])); $itemid = $response['result']['itemids'][0]; self::$itemids[$item['key_']] = $itemid; } return true; } /** * Component configuration provider for agent related tests. * * @return array */ public function serverConfigurationProvider() { return [ self::COMPONENT_SERVER => [ 'LogFileSize' => 0, 'DebugLevel' => 5 ] ]; } /** * Push value of every type. * * @backup history_uint,history_text,history,history_str,history_log */ public function testHistoryPush_pushSingleTrapperValue() { $tcs = [ [ 'itemid' => self::$itemids['trapper_uint'], 'value' => 1, 'value_type' => ITEM_VALUE_TYPE_UINT64 ], [ 'itemid' => self::$itemids['trapper_log'], 'value' => 'somelog', 'value_type' => ITEM_VALUE_TYPE_LOG ], [ 'itemid' => self::$itemids['trapper_float'], 'value' => 1.7, 'value_type' => ITEM_VALUE_TYPE_FLOAT ], [ 'itemid' => self::$itemids['trapper_str'], 'value' => 'somestr', 'value_type' => ITEM_VALUE_TYPE_STR ], [ 'itemid' => self::$itemids['http_agent_text'], 'value' => 'sometext', 'value_type' => ITEM_VALUE_TYPE_TEXT ] ]; foreach ($tcs as $tc) { $value_sent = [ 'itemid' => $tc['itemid'], 'value' => $tc['value'], 'clock' => time() - 25, 'ns' => 255 ]; $response = $this->call('history.push', [ $value_sent ]); $this->assertArrayHasKey('data', $response['result']); $this->assertEquals(1, count($response['result']['data'])); $this->assertArrayHasKey('itemid', $response['result']['data'][0]); $this->assertEquals($tc['itemid'], $response['result']['data'][0]['itemid']); $this->assertArrayNotHasKey('error', $response['result']['data'][0]); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In trapper_process_history_push', true, 95, 3); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of trapper_process_history_push', true, 95, 3); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of DBmass_add_history', true, 95, 3); $response = $this->call('history.get', [ 'output' => ['itemid', 'value', 'clock', 'ns'], 'itemids' => [$tc['itemid']], 'sortorder' => 'DESC', 'sortfield' => 'clock', 'limit' => 1, 'history' => $tc['value_type'] ]); $this->assertEquals(1, count($response['result'])); $value_retrieved = $response['result'][0]; foreach (array_keys($value_retrieved) as $i) { $this->assertEquals(strval($value_sent[$i]), $value_retrieved[$i]); } } return true; } public function testHistoryPush_pushSingleValueHostKey() { $value_sent = [ 'host' => self::HOSTNAME1, 'key' => 'trapper_uint_host_key_test', 'value' => 123, 'clock' => time() - 25, 'ns' => 500 ]; $response = $this->call('history.push', $value_sent); $this->assertArrayHasKey('data', $response['result']); $this->assertEquals(1, count($response['result']['data'])); $this->assertArrayHasKey('itemid', $response['result']['data'][0]); $this->assertEquals(self::$itemids['trapper_uint_host_key_test'], $response['result']['data'][0]['itemid']); $this->assertArrayNotHasKey('error', $response['result']['data'][0]); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In trapper_process_history_push', true, 95, 3); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of trapper_process_history_push', true, 95, 3); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of DBmass_add_history', true, 95, 3); $response = $this->call('history.get', [ 'output' => ['value', 'clock', 'ns'], 'itemids' => [self::$itemids['trapper_uint_host_key_test']], 'sortorder' => 'DESC', 'sortfield' => 'clock', 'limit' => 1 ]); $this->assertEquals(1, count($response['result'])); $value_retrieved = $response['result'][0]; $this->assertEquals($value_sent['value'], $value_retrieved['value']); $this->assertEquals($value_sent['clock'], $value_retrieved['clock']); $this->assertEquals($value_sent['ns'], $value_retrieved['ns']); return true; } /** * Push multiple values of different types in single request. * * @backup history_uint, history_text */ public function testHistoryPush_pushMultipleValues() { $values_sent_uint = []; $values_sent_text = []; $values_sent = []; $idx = 0; for (; $idx < 5; $idx++) { $values_sent_uint[] = [ 'itemid' => self::$itemids['trapper_uint2'], 'value' => 1 + $idx, 'clock' => time() - 20 + $idx, 'ns' => intval(time() / 10000 + 25 * $idx) ]; } for (; $idx < 10; $idx++) { $values_sent_text[] = [ 'itemid' => self::$itemids['trapper_text'], 'value' => "zabbix$idx", 'clock' => time() - 15 + $idx, 'ns' => intval(time() / 10000 + 25 * $idx) ]; } $values_sent = array_merge($values_sent_uint, $values_sent_text); $response = $this->call('history.push', $values_sent); $this->assertArrayHasKey('data', $response['result']); $this->assertEquals(count($values_sent), count($response['result']['data'])); foreach ($response['result']['data'] as $rec) { $this->assertFalse(array_key_exists('error', $rec), "key 'error' exists in a response (itemid: ".$rec['itemid'].")"); } $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'In trapper_process_history_push', true, 95, 3); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of trapper_process_history_push', true, 95, 3); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of DBmass_add_history', true, 95, 3); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of DBmass_add_history', true, 95, 3); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of DBmass_add_history', true, 95, 3); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of DBmass_add_history', true, 95, 3); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of DBmass_add_history', true, 95, 3); $response = $this->call('history.get', [ 'output' => ['itemid', 'value', 'clock', 'ns'], 'history' => ITEM_VALUE_TYPE_TEXT, 'itemids' => self::$itemids['trapper_text'], 'sortfield' => 'clock', 'sortorder' => 'ASC' ]); $this->assertEquals($values_sent_text, $response['result']); $response = $this->call('history.get', [ 'output' => ['itemid', 'value', 'clock', 'ns'], 'itemids' => self::$itemids['trapper_uint2'], 'sortfield' => 'clock', 'sortorder' => 'ASC' ]); $this->assertEquals($values_sent_uint, $response['result']); return true; } public function testHistoryPush_serverIsDown() { $this->stopComponent(self::COMPONENT_SERVER); // CAPITest::call() has assertions for 'result' key in a response, these will throw an exception $this->expectException(\PHPUnit\Framework\ExpectationFailedException::class); $response = $this->call('history.push', [ 'itemid' => self::$itemids['trapper_uint'], 'value' => 1, 'clock' => time() - 25, 'ns' => 255 ]); } public function testHistoryPush_httpAgentTrappingDisabled() { $response = $this->call('history.push', [ 'itemid' => self::$itemids['http_agent_text_no_trap'], 'value' => 'a', 'clock' => time() - 25, 'ns' => 255 ]); $this->assertArrayHasKey('data', $response['result']); $this->assertArrayHasKey(0, $response['result']['data']); $this->assertArrayHasKey('error', $response['result']['data'][0]); } public function testHistoryPush_invalidItemid() { $response = $this->call('history.push', [ 'itemid' => 99999, 'value' => 1, 'clock' => time() - 25, 'ns' => 255 ]); $this->assertArrayHasKey('data', $response['result']); $this->assertArrayHasKey(0, $response['result']['data']); $this->assertArrayHasKey('error', $response['result']['data'][0]); } public function testHistoryPush_disabledItem() { $response = $this->call('history.push', [ 'itemid' => self::$itemids['trapper_uint_disabled'], 'value' => 1, 'clock' => time() - 25, 'ns' => 255 ]); $this->assertArrayHasKey('data', $response['result']); $this->assertArrayHasKey(0, $response['result']['data']); $this->assertArrayHasKey('error', $response['result']['data'][0]); } public function testHistoryPush_notSupportedItemType() { $response = $this->call('history.push', [ 'itemid' => self::$itemids['calc_item'], 'value' => 'x', 'clock' => time() - 25, 'ns' => 255 ]); $this->assertArrayHasKey('data', $response['result']); $this->assertArrayHasKey(0, $response['result']['data']); $this->assertArrayHasKey('error', $response['result']['data'][0]); } public function testHistoryPush_nonMonitoredHost() { $response = $this->call('host.update', [ 'hostid' => self::$hostid_non_monitored, 'status' => 1 ]); $this->reloadConfigurationCache(); $response = $this->call('history.push', [ 'itemid' => self::$itemids['trapper_uint_non_monitored_host'], 'value' => 999, 'clock' => time() - 25, 'ns' => 255 ]); $this->assertArrayHasKey('data', $response['result']); $this->assertArrayHasKey(0, $response['result']['data']); $this->assertArrayHasKey('error', $response['result']['data'][0]); } public function testHistoryPush_hostUnderMaintenance() { $maint_start_tm = time(); $maint_end_tm = $maint_start_tm + 60 * 2; $response = $this->call('maintenance.create', [ 'name' => 'Test maintenance', 'hosts' => ['hostid' => self::$hostid_maintained], 'active_since' => $maint_start_tm, 'active_till' => $maint_end_tm, 'maintenance_type' => MAINTENANCE_TYPE_NODATA, 'timeperiods' => [ 'timeperiod_type' => TIMEPERIOD_TYPE_ONETIME, 'period' => 300, 'start_date' => $maint_start_tm ] ]); $this->assertArrayHasKey('maintenanceids', $response['result']); $this->assertEquals(1, count($response['result']['maintenanceids'])); $maintenance_id = $response['result']['maintenanceids'][0]; $this->reloadConfigurationCache(); $this->waitForLogLineToBePresent(self::COMPONENT_SERVER, 'End of zbx_dc_update_maintenances() started:1 stopped:0 running:1', true); $response = $this->call('history.push', [ 'itemid' => self::$itemids['trapper_uint_maintained_host'], 'value' => 12345, 'clock' => time() - 25, 'ns' => 255 ]); $this->assertArrayHasKey('data', $response['result']); $this->assertArrayHasKey(0, $response['result']['data']); $this->assertArrayHasKey('error', $response['result']['data'][0]); } public function testHistoryPush_clientNotInAllowedHosts() { $response = $this->call('history.push', [ 'itemid' => self::$itemids['trapper_text_bad_allow_hosts'], 'value' => 12345, 'clock' => time() - 25, 'ns' => 255 ]); $this->assertArrayHasKey('data', $response['result']); $this->assertArrayHasKey(0, $response['result']['data']); $this->assertArrayHasKey('error', $response['result']['data'][0]); } public function testHistoryPush_noPermission() { $response = $this->call('user.create', [ 'username' => 'John', 'passwd' => 'Doe123123', 'roleid' => 1, 'usrgrps' => [['usrgrpid' => 8]] ]); $this->assertArrayHasKey('userids', $response['result']); $this->assertArrayHasKey(0, $response['result']['userids']); $userid = $response['result']['userids'][0]; $this->authorize('John', 'Doe123123'); $value_sent = [ 'itemid' => self::$itemids['trapper_uint_no_perms'], 'value' => 1, 'clock' => time() - 25, 'ns' => 255 ]; $response = $this->call('history.push', [ $value_sent ]); $this->assertArrayHasKey('data', $response['result']); $this->assertArrayHasKey(0, $response['result']['data']); $this->assertArrayHasKey('error', $response['result']['data'][0]); } public function testHistoryPush_duplicateTimestamp() { $tm = time(); $response = $this->call('history.push', [ [ 'itemid' => self::$itemids['trapper_uint'], 'value' => 1, 'clock' => $tm, 'ns' => 500 ], [ 'itemid' => self::$itemids['trapper_uint'], 'value' => 0, 'clock' => $tm, 'ns' => 500 ] ]); $this->assertEquals(2, count($response['result']['data'])); $this->assertArrayNotHasKey('error', $response['result']['data'][0]); $this->assertArrayHasKey('error', $response['result']['data'][1]); } public function testHistoryPush_malformedRequest() { // CAPITest::call() has assertions for 'result' key in a response, these will throw an exception $this->expectException(\PHPUnit\Framework\ExpectationFailedException::class); $response = $this->call('history.push', [ [ 'host' => "10000", 'value' => 1, 'clock' => time(), 'ns' => 500 ] ]); } }