224 lines
7.3 KiB
Python
224 lines
7.3 KiB
Python
#
|
|
# Copyright 2022 Red Hat, Inc
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
"""Tests for ceilometer/publisher/tcp.py"""
|
|
|
|
import datetime
|
|
from unittest import mock
|
|
|
|
import msgpack
|
|
from oslo_utils import netutils
|
|
from oslotest import base
|
|
|
|
from ceilometer.publisher import tcp
|
|
from ceilometer.publisher import utils
|
|
from ceilometer import sample
|
|
from ceilometer import service
|
|
|
|
|
|
COUNTER_SOURCE = 'testsource'
|
|
|
|
|
|
class TestTCPPublisher(base.BaseTestCase):
|
|
test_data = [
|
|
sample.Sample(
|
|
name='test',
|
|
type=sample.TYPE_CUMULATIVE,
|
|
unit='',
|
|
volume=1,
|
|
user_id='test',
|
|
project_id='test',
|
|
resource_id='test_run_tasks',
|
|
timestamp=datetime.datetime.utcnow().isoformat(),
|
|
resource_metadata={'name': 'TestPublish'},
|
|
source=COUNTER_SOURCE,
|
|
),
|
|
sample.Sample(
|
|
name='test',
|
|
type=sample.TYPE_CUMULATIVE,
|
|
unit='',
|
|
volume=1,
|
|
user_id='test',
|
|
project_id='test',
|
|
resource_id='test_run_tasks',
|
|
timestamp=datetime.datetime.utcnow().isoformat(),
|
|
resource_metadata={'name': 'TestPublish'},
|
|
source=COUNTER_SOURCE,
|
|
),
|
|
sample.Sample(
|
|
name='test2',
|
|
type=sample.TYPE_CUMULATIVE,
|
|
unit='',
|
|
volume=1,
|
|
user_id='test',
|
|
project_id='test',
|
|
resource_id='test_run_tasks',
|
|
timestamp=datetime.datetime.utcnow().isoformat(),
|
|
resource_metadata={'name': 'TestPublish'},
|
|
source=COUNTER_SOURCE,
|
|
),
|
|
sample.Sample(
|
|
name='test2',
|
|
type=sample.TYPE_CUMULATIVE,
|
|
unit='',
|
|
volume=1,
|
|
user_id='test',
|
|
project_id='test',
|
|
resource_id='test_run_tasks',
|
|
timestamp=datetime.datetime.utcnow().isoformat(),
|
|
resource_metadata={'name': 'TestPublish'},
|
|
source=COUNTER_SOURCE,
|
|
),
|
|
sample.Sample(
|
|
name='test3',
|
|
type=sample.TYPE_CUMULATIVE,
|
|
unit='',
|
|
volume=1,
|
|
user_id='test',
|
|
project_id='test',
|
|
resource_id='test_run_tasks',
|
|
timestamp=datetime.datetime.utcnow().isoformat(),
|
|
resource_metadata={'name': 'TestPublish'},
|
|
source=COUNTER_SOURCE,
|
|
),
|
|
]
|
|
|
|
@staticmethod
|
|
def _make_fake_socket(published):
|
|
def _fake_socket_socket(family, type):
|
|
def record_data(msg):
|
|
msg_length = int.from_bytes(msg[0:8], "little")
|
|
published.append(msg[8:msg_length + 8])
|
|
|
|
def connect(dst):
|
|
pass
|
|
|
|
tcp_socket = mock.Mock()
|
|
tcp_socket.send = record_data
|
|
tcp_socket.connect = connect
|
|
return tcp_socket
|
|
|
|
return _fake_socket_socket
|
|
|
|
def setUp(self):
|
|
super(TestTCPPublisher, self).setUp()
|
|
self.CONF = service.prepare_service([], [])
|
|
self.CONF.publisher.telemetry_secret = 'not-so-secret'
|
|
|
|
def test_published(self):
|
|
self.data_sent = []
|
|
with mock.patch('socket.socket',
|
|
self._make_fake_socket(self.data_sent)):
|
|
publisher = tcp.TCPPublisher(
|
|
self.CONF,
|
|
netutils.urlsplit('tcp://somehost'))
|
|
publisher.publish_samples(self.test_data)
|
|
|
|
self.assertEqual(5, len(self.data_sent))
|
|
|
|
sent_counters = []
|
|
|
|
for data in self.data_sent:
|
|
counter = msgpack.loads(data, raw=False)
|
|
sent_counters.append(counter)
|
|
|
|
# Check that counters are equal
|
|
def sort_func(counter):
|
|
return counter['counter_name']
|
|
|
|
counters = [utils.meter_message_from_counter(d,
|
|
"not-so-secret",
|
|
publisher.conf.host)
|
|
for d in self.test_data]
|
|
counters.sort(key=sort_func)
|
|
sent_counters.sort(key=sort_func)
|
|
self.assertEqual(counters, sent_counters)
|
|
|
|
@staticmethod
|
|
def _make_disconnecting_socket(published, connections):
|
|
def _fake_socket_socket(family, type):
|
|
def record_data(msg):
|
|
if len(published) == len(connections) - 1:
|
|
# Raise for every each first send attempt to
|
|
# trigger a reconnection attempt and send the data
|
|
# correctly after reconnecting
|
|
raise IOError
|
|
msg_length = int.from_bytes(msg[0:8], "little")
|
|
published.append(msg[8:msg_length + 8])
|
|
|
|
def record_connection(dest):
|
|
connections.append(dest)
|
|
|
|
tcp_socket = mock.Mock()
|
|
tcp_socket.send = record_data
|
|
tcp_socket.connect = record_connection
|
|
return tcp_socket
|
|
|
|
return _fake_socket_socket
|
|
|
|
def test_reconnect(self):
|
|
self.data_sent = []
|
|
self.connections = []
|
|
with mock.patch('socket.socket',
|
|
self._make_disconnecting_socket(self.data_sent,
|
|
self.connections)):
|
|
publisher = tcp.TCPPublisher(
|
|
self.CONF,
|
|
netutils.urlsplit('tcp://somehost'))
|
|
publisher.publish_samples(self.test_data)
|
|
|
|
sent_counters = []
|
|
|
|
for data in self.data_sent:
|
|
counter = msgpack.loads(data, raw=False)
|
|
sent_counters.append(counter)
|
|
|
|
for connection in self.connections:
|
|
# Check destination
|
|
self.assertEqual(('somehost', 4952), connection)
|
|
self.assertEqual(len(self.connections) - 1, len(self.data_sent))
|
|
|
|
# Check that counters are equal
|
|
def sort_func(counter):
|
|
return counter['counter_name']
|
|
|
|
counters = [utils.meter_message_from_counter(d,
|
|
"not-so-secret",
|
|
publisher.conf.host)
|
|
for d in self.test_data]
|
|
counters.sort(key=sort_func)
|
|
sent_counters.sort(key=sort_func)
|
|
self.assertEqual(counters, sent_counters)
|
|
|
|
@staticmethod
|
|
def _raise_ioerror(*args):
|
|
raise IOError
|
|
|
|
def _make_broken_socket(self, family, type):
|
|
def connect(dst):
|
|
pass
|
|
|
|
tcp_socket = mock.Mock()
|
|
tcp_socket.send = self._raise_ioerror
|
|
tcp_socket.connect = connect
|
|
return tcp_socket
|
|
|
|
def test_publish_error(self):
|
|
with mock.patch('socket.socket',
|
|
self._make_broken_socket):
|
|
publisher = tcp.TCPPublisher(
|
|
self.CONF,
|
|
netutils.urlsplit('tcp://localhost'))
|
|
publisher.publish_samples(self.test_data)
|