New test case: "test_connection_limit"

Traffic based test, that is planned to validate "connection_limit"
functionality. Once set, LB should limit clients' connections
(parallel sessions) to the set value.

Change-Id: I3cf49f6281529058b86b88501872292771812c6c
This commit is contained in:
Arkady Shtempler 2021-02-24 17:46:51 +02:00
parent c50539cc07
commit b6d71a7d12
2 changed files with 102 additions and 0 deletions

View File

@ -19,6 +19,8 @@ import socket
import testtools
import time
from threading import Thread
from oslo_log import log as logging
from oslo_utils import uuidutils
from tempest import config
@ -1391,3 +1393,65 @@ class TrafficOperationsScenarioTest(test_base.LoadBalancerBaseTestWithCompute):
listener_port), const.X_FORWARDED_PROTO: const.HTTP.lower()}
received_headers = _data_parser(data, expected_headers)
self.assertEqual(expected_headers, received_headers)
@decorators.idempotent_id('45f5f018-1073-11eb-be7b-74e5f9e2a801')
def test_connection_limit(self):
"""Test scenario:
* Create LB, HTTP listener, pool, 2 members and validate traffic.
* Update listener's "connection_limit" to "X", wait till
* configuration is done.
* Start HTTP traffic - parallel TCP connections that are doubled
* than configured "connection_limit", it means (X*2)
* Assertion - test fails if the amount of "Failed TCP connections"
* is less than total TCP connections ("X/2")sent in parallel.
"""
listener_port = 104
listener_id, pool_id = self._listener_pool_create(
const.HTTP, listener_port)
self._test_basic_traffic(
const.HTTP, listener_port, pool_id, persistent=False)
# Update listener's "connection_limit" to: <connection_limit> value.
connection_limit = 5
listener_kwargs = {
const.LISTENER_ID: listener_id,
const.CONNECTION_LIMIT: connection_limit}
self.mem_listener_client.update_listener(**listener_kwargs)
waiters.wait_for_status(self.mem_lb_client.show_loadbalancer,
self.lb_id, const.PROVISIONING_STATUS,
const.ACTIVE,
CONF.load_balancer.build_interval,
CONF.load_balancer.build_timeout)
# Start the traffic, using parallel TCP connections.
# The number of TCP connection is "doubled" than the amount of
# configured connection limit set.
connections_number = connection_limit * 2
http_gets_per_connection = 10
delay_between_http_gets = 0.1
threads = [None] * connections_number
traffic_result_limited = [None] * connections_number
for i in range(len(threads)):
threads[i] = Thread(
target=self._http_requests_single_connection,
args=(self.lb_vip_address, listener_port,
http_gets_per_connection, delay_between_http_gets,
traffic_result_limited, i))
threads[i].start()
for i in range(len(threads)):
threads[i].join()
LOG.info('test_connection_limit traffic_result_limited: '
+ str(traffic_result_limited))
# Assertion - test fails if the amount of "Failed Connections"
# is less than "total TCP connections sent"/2
failed_connections_limited = len(
[item for item in traffic_result_limited
if item['ConnectionStatus'] is False])
LOG.info('test_connection_limit failed_connections_limited: '
+ str(failed_connections_limited))
self.assertGreaterEqual(
failed_connections_limited,
connections_number/2,
'Failed - the number of failed connections is less than expected!')

View File

@ -421,3 +421,41 @@ class ValidatorsMixin(test.BaseTestCase):
protocol_port))
LOG.error(message)
raise Exception(message)
@staticmethod
def _http_requests_single_connection(
dst_ip, dst_port, request_number,
delay, result, index, tcp_timeout=1):
"""This function is used as a thread target function.
:param dst_ip: Destination HTTP server IP.
:param dst_port: Destination HTTP server port.
:param request_number: A number of subsequent GET requests to be sent
on the same TCP connection/session.
:param delay: Delay in [sec] between the GET requests.
:param result: A list of Nones: [None, None..., None] as a number of
threads to be started. Each thread will then update appropriate
item in this list with its own retrieved data.
:param index: Indexing the threads.
:param tcp_timeout: Python Requests module TCP timeout.
:return: Updated by threads "result" list, for example 1 threads
with a single GET may look like this:
[{'ConnectionStatus': True,
'RespondData': [{'RequestNumber': 0,'ResponseCode': 200,
'ResponseContentSize': 1}]
"""
try:
s = requests.Session()
responses = []
for req in range(0, request_number):
r = s.get('http://'+dst_ip+':'+str(dst_port),
timeout=tcp_timeout)
responses.append({
'RequestNumber': req, 'ResponseCode': r.status_code,
'ResponseContentSize': len(r.content)})
time.sleep(delay)
result[index] = {
'ConnectionStatus': True, 'RespondData': responses}
except Exception as e:
result[index] = {'ConnectionStatus': False, 'RespondData': e}