Add limit batches option to start stream query (#392)
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
# licenses/APL.txt.
|
||||
|
||||
import mgclient
|
||||
import pytest
|
||||
import time
|
||||
|
||||
from multiprocessing import Manager, Process, Value
|
||||
@@ -112,6 +113,13 @@ def start_stream(cursor, stream_name):
|
||||
assert get_is_running(cursor, stream_name)
|
||||
|
||||
|
||||
def start_stream_with_limit(cursor, stream_name, batch_limit, timeout=None):
|
||||
if timeout is not None:
|
||||
execute_and_fetch_all(cursor, f"START STREAM {stream_name} BATCH_LIMIT {batch_limit} TIMEOUT {timeout} ")
|
||||
else:
|
||||
execute_and_fetch_all(cursor, f"START STREAM {stream_name} BATCH_LIMIT {batch_limit}")
|
||||
|
||||
|
||||
def stop_stream(cursor, stream_name):
|
||||
execute_and_fetch_all(cursor, f"STOP STREAM {stream_name}")
|
||||
|
||||
@@ -253,10 +261,11 @@ def test_start_checked_stream_after_timeout(connection, stream_creator):
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, stream_creator("test_stream"))
|
||||
|
||||
TIMEOUT_MS = 2000
|
||||
TIMEOUT_IN_MS = 2000
|
||||
TIMEOUT_IN_SECONDS = TIMEOUT_IN_MS / 1000
|
||||
|
||||
def call_check():
|
||||
execute_and_fetch_all(connect().cursor(), f"CHECK STREAM test_stream TIMEOUT {TIMEOUT_MS}")
|
||||
execute_and_fetch_all(connect().cursor(), f"CHECK STREAM test_stream TIMEOUT {TIMEOUT_IN_MS}")
|
||||
|
||||
check_stream_proc = Process(target=call_check, daemon=True)
|
||||
|
||||
@@ -266,7 +275,7 @@ def test_start_checked_stream_after_timeout(connection, stream_creator):
|
||||
start_stream(cursor, "test_stream")
|
||||
end = time.time()
|
||||
|
||||
assert (end - start) < 1.3 * TIMEOUT_MS, "The START STREAM was blocked too long"
|
||||
assert (end - start) < 1.3 * TIMEOUT_IN_SECONDS, "The START STREAM was blocked too long"
|
||||
assert get_is_running(cursor, "test_stream")
|
||||
stop_stream(cursor, "test_stream")
|
||||
|
||||
@@ -401,3 +410,239 @@ def test_check_stream_different_number_of_queries_than_messages(connection, stre
|
||||
assert expected_queries_and_raw_messages_1 == results.value[0]
|
||||
assert expected_queries_and_raw_messages_2 == results.value[1]
|
||||
assert expected_queries_and_raw_messages_3 == results.value[2]
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit(connection, stream_creator, messages_sender):
|
||||
STREAM_NAME = "test"
|
||||
BATCH_LIMIT = 5
|
||||
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, stream_creator(STREAM_NAME))
|
||||
|
||||
def start_new_stream_with_limit(stream_name, batch_limit):
|
||||
connection = connect()
|
||||
cursor = connection.cursor()
|
||||
start_stream_with_limit(cursor, stream_name, batch_limit)
|
||||
|
||||
thread_stream_running = Process(target=start_new_stream_with_limit, daemon=True, args=(STREAM_NAME, BATCH_LIMIT))
|
||||
thread_stream_running.start()
|
||||
|
||||
time.sleep(2)
|
||||
assert get_is_running(cursor, STREAM_NAME)
|
||||
|
||||
messages_sender(BATCH_LIMIT - 1)
|
||||
|
||||
# We have not sent enough batches to reach the limit. We check that the stream is still correctly running.
|
||||
assert get_is_running(cursor, STREAM_NAME)
|
||||
|
||||
# We send a last message to reach the batch_limit
|
||||
messages_sender(1)
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
# We check that the stream has correctly stoped.
|
||||
assert not get_is_running(cursor, STREAM_NAME)
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit_timeout(connection, stream_creator):
|
||||
# We check that we get the expected exception when trying to run START STREAM while providing TIMEOUT and not BATCH_LIMIT
|
||||
STREAM_NAME = "test"
|
||||
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, stream_creator(STREAM_NAME))
|
||||
|
||||
with pytest.raises(mgclient.DatabaseError):
|
||||
execute_and_fetch_all(cursor, f"START STREAM {STREAM_NAME} TIMEOUT 3000")
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit_reaching_timeout(connection, stream_creator):
|
||||
# We check that we get the expected exception when running START STREAM while providing TIMEOUT and BATCH_LIMIT
|
||||
STREAM_NAME = "test"
|
||||
BATCH_LIMIT = 5
|
||||
TIMEOUT = 3000
|
||||
TIMEOUT_IN_SECONDS = TIMEOUT / 1000
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, stream_creator(STREAM_NAME, BATCH_SIZE))
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
with pytest.raises(mgclient.DatabaseError):
|
||||
execute_and_fetch_all(cursor, f"START STREAM {STREAM_NAME} BATCH_LIMIT {BATCH_LIMIT} TIMEOUT {TIMEOUT}")
|
||||
|
||||
end_time = time.time()
|
||||
assert (
|
||||
end_time - start_time
|
||||
) >= TIMEOUT_IN_SECONDS, "The START STREAM has probably thrown due to something else than timeout!"
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit_while_check_running(
|
||||
connection, stream_creator, message_sender, setup_function=None
|
||||
):
|
||||
# 1/ We check we get the correct exception calling START STREAM with BATCH_LIMIT while a CHECK STREAM is already running.
|
||||
# 2/ Afterwards, we terminate the CHECK STREAM and start a START STREAM with BATCH_LIMIT
|
||||
def start_check_stream(stream_name, batch_limit, timeout):
|
||||
connection = connect()
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, f"CHECK STREAM {stream_name} BATCH_LIMIT {batch_limit} TIMEOUT {timeout}")
|
||||
|
||||
def start_new_stream_with_limit(stream_name, batch_limit, timeout):
|
||||
connection = connect()
|
||||
cursor = connection.cursor()
|
||||
start_stream_with_limit(cursor, stream_name, batch_limit, timeout=timeout)
|
||||
|
||||
STREAM_NAME = "test_check_and_batch_limit"
|
||||
BATCH_LIMIT = 1
|
||||
TIMEOUT = 10000
|
||||
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, stream_creator(STREAM_NAME))
|
||||
|
||||
# 0/ Extra setup needed for Kafka to works correctly if Check stream is execute before any messages have been consumed.
|
||||
if setup_function is not None:
|
||||
setup_function(start_check_stream, cursor, STREAM_NAME, BATCH_LIMIT, TIMEOUT)
|
||||
|
||||
# 1/
|
||||
thread_stream_check = Process(target=start_check_stream, daemon=True, args=(STREAM_NAME, BATCH_LIMIT, TIMEOUT))
|
||||
thread_stream_check.start()
|
||||
time.sleep(2)
|
||||
assert get_is_running(cursor, STREAM_NAME)
|
||||
|
||||
with pytest.raises(mgclient.DatabaseError):
|
||||
start_stream_with_limit(cursor, STREAM_NAME, BATCH_LIMIT, timeout=TIMEOUT)
|
||||
|
||||
assert get_is_running(cursor, STREAM_NAME)
|
||||
message_sender(SIMPLE_MSG)
|
||||
thread_stream_check.join()
|
||||
|
||||
assert not get_is_running(cursor, STREAM_NAME)
|
||||
|
||||
# 2/
|
||||
thread_stream_running = Process(
|
||||
target=start_new_stream_with_limit, daemon=True, args=(STREAM_NAME, BATCH_LIMIT + 1, TIMEOUT)
|
||||
) # Sending BATCH_LIMIT + 1 messages as BATCH_LIMIT messages have already been sent during the CHECK STREAM (and not consumed)
|
||||
thread_stream_running.start()
|
||||
time.sleep(2)
|
||||
assert get_is_running(cursor, STREAM_NAME)
|
||||
|
||||
message_sender(SIMPLE_MSG)
|
||||
time.sleep(2)
|
||||
|
||||
assert not get_is_running(cursor, STREAM_NAME)
|
||||
|
||||
|
||||
def test_check_while_stream_with_batch_limit_running(connection, stream_creator, message_sender):
|
||||
# 1/ We check we get the correct exception calling CHECK STREAM while START STREAM with BATCH_LIMIT is already running
|
||||
# 2/ Afterwards, we terminate the START STREAM with BATCH_LIMIT and start a CHECK STREAM
|
||||
def start_new_stream_with_limit(stream_name, batch_limit, timeout):
|
||||
connection = connect()
|
||||
cursor = connection.cursor()
|
||||
start_stream_with_limit(cursor, stream_name, batch_limit, timeout=timeout)
|
||||
|
||||
def start_check_stream(stream_name, batch_limit, timeout):
|
||||
connection = connect()
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, f"CHECK STREAM {stream_name} BATCH_LIMIT {batch_limit} TIMEOUT {timeout}")
|
||||
|
||||
STREAM_NAME = "test_batch_limit_and_check"
|
||||
BATCH_LIMIT = 1
|
||||
TIMEOUT = 10000
|
||||
TIMEOUT_IN_SECONDS = TIMEOUT / 1000
|
||||
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, stream_creator(STREAM_NAME))
|
||||
|
||||
# 1/
|
||||
thread_stream_running = Process(
|
||||
target=start_new_stream_with_limit, daemon=True, args=(STREAM_NAME, BATCH_LIMIT, TIMEOUT)
|
||||
)
|
||||
start_time = time.time()
|
||||
thread_stream_running.start()
|
||||
time.sleep(2)
|
||||
assert get_is_running(cursor, STREAM_NAME)
|
||||
|
||||
with pytest.raises(mgclient.DatabaseError):
|
||||
execute_and_fetch_all(cursor, f"CHECK STREAM {STREAM_NAME} BATCH_LIMIT {BATCH_LIMIT} TIMEOUT {TIMEOUT}")
|
||||
|
||||
end_time = time.time()
|
||||
assert (end_time - start_time) < 0.8 * TIMEOUT, "The CHECK STREAM has probably thrown due to timeout!"
|
||||
|
||||
message_sender(SIMPLE_MSG)
|
||||
time.sleep(2)
|
||||
|
||||
assert not get_is_running(cursor, STREAM_NAME)
|
||||
|
||||
# 2/
|
||||
thread_stream_check = Process(target=start_check_stream, daemon=True, args=(STREAM_NAME, BATCH_LIMIT, TIMEOUT))
|
||||
start_time = time.time()
|
||||
thread_stream_check.start()
|
||||
time.sleep(2)
|
||||
assert get_is_running(cursor, STREAM_NAME)
|
||||
|
||||
message_sender(SIMPLE_MSG)
|
||||
time.sleep(2)
|
||||
end_time = time.time()
|
||||
assert (end_time - start_time) < 0.8 * TIMEOUT_IN_SECONDS, "The CHECK STREAM has probably thrown due to timeout!"
|
||||
|
||||
assert not get_is_running(cursor, STREAM_NAME)
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit_with_invalid_batch_limit(connection, stream_creator):
|
||||
# We check that we get a correct exception when giving a negative batch_limit
|
||||
STREAM_NAME = "test_batch_limit_invalid_batch_limit"
|
||||
TIMEOUT = 10000
|
||||
TIMEOUT_IN_SECONDS = TIMEOUT / 1000
|
||||
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, stream_creator(STREAM_NAME))
|
||||
time.sleep(2)
|
||||
|
||||
# 1/ checking with batch_limit=-10
|
||||
batch_limit = -10
|
||||
start_time = time.time()
|
||||
|
||||
with pytest.raises(mgclient.DatabaseError):
|
||||
start_stream_with_limit(cursor, STREAM_NAME, batch_limit, timeout=TIMEOUT)
|
||||
|
||||
end_time = time.time()
|
||||
assert (end_time - start_time) < 0.8 * TIMEOUT_IN_SECONDS, "The START STREAM has probably thrown due to timeout!"
|
||||
|
||||
# 2/ checking with batch_limit=0
|
||||
batch_limit = 0
|
||||
start_time = time.time()
|
||||
|
||||
with pytest.raises(mgclient.DatabaseError):
|
||||
start_stream_with_limit(cursor, STREAM_NAME, batch_limit, timeout=TIMEOUT)
|
||||
|
||||
end_time = time.time()
|
||||
assert (end_time - start_time) < 0.8 * TIMEOUT_IN_SECONDS, "The START STREAM has probably thrown due to timeout!"
|
||||
|
||||
|
||||
def test_check_stream_with_batch_limit_with_invalid_batch_limit(connection, stream_creator):
|
||||
# We check that we get a correct exception when giving a negative batch_limit
|
||||
STREAM_NAME = "test_batch_limit_invalid_batch_limit"
|
||||
TIMEOUT = 10000
|
||||
TIMEOUT_IN_SECONDS = TIMEOUT / 1000
|
||||
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, stream_creator(STREAM_NAME))
|
||||
time.sleep(2)
|
||||
|
||||
# 1/ checking with batch_limit=-10
|
||||
batch_limit = -10
|
||||
start_time = time.time()
|
||||
|
||||
with pytest.raises(mgclient.DatabaseError):
|
||||
execute_and_fetch_all(cursor, f"CHECK STREAM {STREAM_NAME} BATCH_LIMIT {batch_limit} TIMEOUT {TIMEOUT}")
|
||||
|
||||
end_time = time.time()
|
||||
assert (end_time - start_time) < 0.8 * TIMEOUT_IN_SECONDS, "The CHECK STREAM has probably thrown due to timeout!"
|
||||
|
||||
# 2/ checking with batch_limit=0
|
||||
batch_limit = 0
|
||||
start_time = time.time()
|
||||
|
||||
with pytest.raises(mgclient.DatabaseError):
|
||||
execute_and_fetch_all(cursor, f"CHECK STREAM {STREAM_NAME} BATCH_LIMIT {batch_limit} TIMEOUT {TIMEOUT}")
|
||||
|
||||
end_time = time.time()
|
||||
assert (end_time - start_time) < 0.8 * TIMEOUT_IN_SECONDS, "The CHECK STREAM has probably thrown due to timeout!"
|
||||
|
||||
@@ -18,7 +18,7 @@ import time
|
||||
from multiprocessing import Process, Value
|
||||
import common
|
||||
|
||||
TRANSFORMATIONS_TO_CHECK_C = ["empty_transformation"]
|
||||
TRANSFORMATIONS_TO_CHECK_C = ["c_transformations.empty_transformation"]
|
||||
|
||||
TRANSFORMATIONS_TO_CHECK_PY = ["kafka_transform.simple", "kafka_transform.with_parameters"]
|
||||
|
||||
@@ -381,10 +381,11 @@ def test_info_procedure(kafka_topics, connection):
|
||||
@pytest.mark.parametrize("transformation", TRANSFORMATIONS_TO_CHECK_C)
|
||||
def test_load_c_transformations(connection, transformation):
|
||||
cursor = connection.cursor()
|
||||
query = f"CALL mg.transformations() YIELD * WITH name WHERE name STARTS WITH 'c_transformations.{transformation}' RETURN name"
|
||||
|
||||
query = f"CALL mg.transformations() YIELD * WITH name WHERE name STARTS WITH '{transformation}' RETURN name"
|
||||
result = common.execute_and_fetch_all(cursor, query)
|
||||
assert len(result) == 1
|
||||
assert result[0][0] == f"c_transformations.{transformation}"
|
||||
assert result[0][0] == transformation
|
||||
|
||||
|
||||
def test_check_stream_same_number_of_queries_than_messages(kafka_producer, kafka_topics, connection):
|
||||
@@ -415,5 +416,100 @@ def test_check_stream_different_number_of_queries_than_messages(kafka_producer,
|
||||
common.test_check_stream_different_number_of_queries_than_messages(connection, stream_creator, message_sender)
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit(kafka_producer, kafka_topics, connection):
|
||||
assert len(kafka_topics) > 0
|
||||
|
||||
def stream_creator(stream_name):
|
||||
return (
|
||||
f"CREATE KAFKA STREAM {stream_name} TOPICS {kafka_topics[0]} TRANSFORM kafka_transform.simple BATCH_SIZE 1"
|
||||
)
|
||||
|
||||
def messages_sender(nof_messages):
|
||||
for x in range(nof_messages):
|
||||
kafka_producer.send(kafka_topics[0], common.SIMPLE_MSG).get(timeout=60)
|
||||
|
||||
common.test_start_stream_with_batch_limit(connection, stream_creator, messages_sender)
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit_timeout(kafka_producer, kafka_topics, connection):
|
||||
assert len(kafka_topics) > 0
|
||||
|
||||
def stream_creator(stream_name):
|
||||
return (
|
||||
f"CREATE KAFKA STREAM {stream_name} TOPICS {kafka_topics[0]} TRANSFORM kafka_transform.simple BATCH_SIZE 1"
|
||||
)
|
||||
|
||||
common.test_start_stream_with_batch_limit_timeout(connection, stream_creator)
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit_reaching_timeout(kafka_producer, kafka_topics, connection):
|
||||
assert len(kafka_topics) > 0
|
||||
|
||||
def stream_creator(stream_name, batch_size):
|
||||
return f"CREATE KAFKA STREAM {stream_name} TOPICS {kafka_topics[0]} TRANSFORM kafka_transform.simple BATCH_SIZE {batch_size}"
|
||||
|
||||
common.test_start_stream_with_batch_limit_reaching_timeout(connection, stream_creator)
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit_while_check_running(kafka_producer, kafka_topics, connection):
|
||||
assert len(kafka_topics) > 0
|
||||
|
||||
def stream_creator(stream_name):
|
||||
return (
|
||||
f"CREATE KAFKA STREAM {stream_name} TOPICS {kafka_topics[0]} TRANSFORM kafka_transform.simple BATCH_SIZE 1"
|
||||
)
|
||||
|
||||
def message_sender(message):
|
||||
kafka_producer.send(kafka_topics[0], message).get(timeout=6000)
|
||||
|
||||
def setup_function(start_check_stream, cursor, stream_name, batch_limit, timeout):
|
||||
thread_stream_check = Process(target=start_check_stream, daemon=True, args=(stream_name, batch_limit, timeout))
|
||||
thread_stream_check.start()
|
||||
time.sleep(2)
|
||||
assert common.get_is_running(cursor, stream_name)
|
||||
message_sender(common.SIMPLE_MSG)
|
||||
thread_stream_check.join()
|
||||
|
||||
common.test_start_stream_with_batch_limit_while_check_running(
|
||||
connection, stream_creator, message_sender, setup_function
|
||||
)
|
||||
|
||||
|
||||
def test_check_while_stream_with_batch_limit_running(kafka_producer, kafka_topics, connection):
|
||||
assert len(kafka_topics) > 0
|
||||
|
||||
def stream_creator(stream_name):
|
||||
return (
|
||||
f"CREATE KAFKA STREAM {stream_name} TOPICS {kafka_topics[0]} TRANSFORM kafka_transform.simple BATCH_SIZE 1"
|
||||
)
|
||||
|
||||
def message_sender(message):
|
||||
kafka_producer.send(kafka_topics[0], message).get(timeout=6000)
|
||||
|
||||
common.test_check_while_stream_with_batch_limit_running(connection, stream_creator, message_sender)
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit_with_invalid_batch_limit(kafka_producer, kafka_topics, connection):
|
||||
assert len(kafka_topics) > 0
|
||||
|
||||
def stream_creator(stream_name):
|
||||
return (
|
||||
f"CREATE KAFKA STREAM {stream_name} TOPICS {kafka_topics[0]} TRANSFORM kafka_transform.simple BATCH_SIZE 1"
|
||||
)
|
||||
|
||||
common.test_start_stream_with_batch_limit_with_invalid_batch_limit(connection, stream_creator)
|
||||
|
||||
|
||||
def test_check_stream_with_batch_limit_with_invalid_batch_limit(kafka_producer, kafka_topics, connection):
|
||||
assert len(kafka_topics) > 0
|
||||
|
||||
def stream_creator(stream_name):
|
||||
return (
|
||||
f"CREATE KAFKA STREAM {stream_name} TOPICS {kafka_topics[0]} TRANSFORM kafka_transform.simple BATCH_SIZE 1"
|
||||
)
|
||||
|
||||
common.test_check_stream_with_batch_limit_with_invalid_batch_limit(connection, stream_creator)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main([__file__, "-rA"]))
|
||||
|
||||
@@ -344,6 +344,73 @@ def test_service_url(pulsar_client, pulsar_topics, connection, transformation):
|
||||
check_vertex_exists_with_topic_and_payload(cursor, topic, common.SIMPLE_MSG)
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit(pulsar_client, pulsar_topics, connection):
|
||||
assert len(pulsar_topics) > 1
|
||||
|
||||
def stream_creator(stream_name):
|
||||
return f"CREATE PULSAR STREAM {stream_name} TOPICS {pulsar_topics[0]} TRANSFORM pulsar_transform.simple BATCH_SIZE 1"
|
||||
|
||||
producer = pulsar_client.create_producer(
|
||||
common.pulsar_default_namespace_topic(pulsar_topics[0]), send_timeout_millis=60000
|
||||
)
|
||||
|
||||
def messages_sender(nof_messages):
|
||||
for x in range(nof_messages):
|
||||
producer.send(common.SIMPLE_MSG)
|
||||
|
||||
common.test_start_stream_with_batch_limit(connection, stream_creator, messages_sender)
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit_timeout(pulsar_client, pulsar_topics, connection):
|
||||
assert len(pulsar_topics) > 1
|
||||
|
||||
def stream_creator(stream_name):
|
||||
return f"CREATE PULSAR STREAM {stream_name} TOPICS {pulsar_topics[0]} TRANSFORM pulsar_transform.simple BATCH_SIZE 1"
|
||||
|
||||
common.test_start_stream_with_batch_limit_timeout(connection, stream_creator)
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit_reaching_timeout(pulsar_client, pulsar_topics, connection):
|
||||
assert len(pulsar_topics) > 1
|
||||
|
||||
def stream_creator(stream_name, batch_size):
|
||||
return f"CREATE PULSAR STREAM {stream_name} TOPICS {pulsar_topics[0]} TRANSFORM pulsar_transform.simple BATCH_SIZE {batch_size}"
|
||||
|
||||
common.test_start_stream_with_batch_limit_reaching_timeout(connection, stream_creator)
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit_while_check_running(pulsar_client, pulsar_topics, connection):
|
||||
assert len(pulsar_topics) > 0
|
||||
|
||||
def stream_creator(stream_name):
|
||||
return f"CREATE PULSAR STREAM {stream_name} TOPICS {pulsar_topics[0]} TRANSFORM pulsar_transform.simple BATCH_SIZE 1"
|
||||
|
||||
producer = pulsar_client.create_producer(
|
||||
common.pulsar_default_namespace_topic(pulsar_topics[0]), send_timeout_millis=60000
|
||||
)
|
||||
|
||||
def message_sender(message):
|
||||
producer.send(message)
|
||||
|
||||
common.test_start_stream_with_batch_limit_while_check_running(connection, stream_creator, message_sender)
|
||||
|
||||
|
||||
def test_check_while_stream_with_batch_limit_running(pulsar_client, pulsar_topics, connection):
|
||||
assert len(pulsar_topics) > 0
|
||||
|
||||
def stream_creator(stream_name):
|
||||
return f"CREATE PULSAR STREAM {stream_name} TOPICS {pulsar_topics[0]} TRANSFORM pulsar_transform.simple BATCH_SIZE 1"
|
||||
|
||||
producer = pulsar_client.create_producer(
|
||||
common.pulsar_default_namespace_topic(pulsar_topics[0]), send_timeout_millis=60000
|
||||
)
|
||||
|
||||
def message_sender(message):
|
||||
producer.send(message)
|
||||
|
||||
common.test_check_while_stream_with_batch_limit_running(connection, stream_creator, message_sender)
|
||||
|
||||
|
||||
def test_check_stream_same_number_of_queries_than_messages(pulsar_client, pulsar_topics, connection):
|
||||
assert len(pulsar_topics) > 0
|
||||
|
||||
@@ -380,5 +447,23 @@ def test_check_stream_different_number_of_queries_than_messages(pulsar_client, p
|
||||
common.test_check_stream_different_number_of_queries_than_messages(connection, stream_creator, message_sender)
|
||||
|
||||
|
||||
def test_start_stream_with_batch_limit_with_invalid_batch_limit(pulsar_client, pulsar_topics, connection):
|
||||
assert len(pulsar_topics) > 0
|
||||
|
||||
def stream_creator(stream_name):
|
||||
return f"CREATE PULSAR STREAM {stream_name} TOPICS {pulsar_topics[0]} TRANSFORM pulsar_transform.simple BATCH_SIZE 1"
|
||||
|
||||
common.test_start_stream_with_batch_limit_with_invalid_batch_limit(connection, stream_creator)
|
||||
|
||||
|
||||
def test_check_stream_with_batch_limit_with_invalid_batch_limit(pulsar_client, pulsar_topics, connection):
|
||||
assert len(pulsar_topics) > 0
|
||||
|
||||
def stream_creator(stream_name):
|
||||
return f"CREATE PULSAR STREAM {stream_name} TOPICS {pulsar_topics[0]} TRANSFORM pulsar_transform.simple BATCH_SIZE 1"
|
||||
|
||||
common.test_check_stream_with_batch_limit_with_invalid_batch_limit(connection, stream_creator)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main([__file__, "-rA"]))
|
||||
|
||||
@@ -149,7 +149,7 @@ TEST_F(ConsumerTest, BatchInterval) {
|
||||
}
|
||||
|
||||
consumer->Stop();
|
||||
EXPECT_TRUE(expected_messages_received) << "Some unexpected message have been received";
|
||||
EXPECT_TRUE(expected_messages_received) << "Some unexpected message has been received";
|
||||
|
||||
auto check_received_timestamp = [&received_timestamps](size_t index) {
|
||||
SCOPED_TRACE("Checking index " + std::to_string(index));
|
||||
@@ -178,14 +178,6 @@ TEST_F(ConsumerTest, BatchInterval) {
|
||||
TEST_F(ConsumerTest, StartStop) {
|
||||
Consumer consumer{CreateDefaultConsumerInfo(), kDummyConsumerFunction};
|
||||
|
||||
auto start = [&consumer](const bool use_conditional) {
|
||||
if (use_conditional) {
|
||||
consumer.StartIfStopped();
|
||||
} else {
|
||||
consumer.Start();
|
||||
}
|
||||
};
|
||||
|
||||
auto stop = [&consumer](const bool use_conditional) {
|
||||
if (use_conditional) {
|
||||
consumer.StopIfRunning();
|
||||
@@ -194,34 +186,28 @@ TEST_F(ConsumerTest, StartStop) {
|
||||
}
|
||||
};
|
||||
|
||||
auto check_config = [&start, &stop, &consumer](const bool use_conditional_start,
|
||||
const bool use_conditional_stop) mutable {
|
||||
SCOPED_TRACE(
|
||||
fmt::format("Conditional start {} and conditional stop {}", use_conditional_start, use_conditional_stop));
|
||||
auto check_config = [&stop, &consumer](const bool use_conditional_stop) mutable {
|
||||
SCOPED_TRACE(fmt::format("Start and conditionally stop {}", use_conditional_stop));
|
||||
EXPECT_FALSE(consumer.IsRunning());
|
||||
EXPECT_THROW(consumer.Stop(), ConsumerStoppedException);
|
||||
consumer.StopIfRunning();
|
||||
EXPECT_FALSE(consumer.IsRunning());
|
||||
|
||||
start(use_conditional_start);
|
||||
consumer.Start();
|
||||
EXPECT_TRUE(consumer.IsRunning());
|
||||
EXPECT_THROW(consumer.Start(), ConsumerRunningException);
|
||||
consumer.StartIfStopped();
|
||||
|
||||
EXPECT_TRUE(consumer.IsRunning());
|
||||
|
||||
stop(use_conditional_stop);
|
||||
EXPECT_FALSE(consumer.IsRunning());
|
||||
};
|
||||
|
||||
static constexpr auto kSimpleStart = false;
|
||||
static constexpr auto kSimpleStop = false;
|
||||
static constexpr auto kConditionalStart = true;
|
||||
static constexpr auto kConditionalStop = true;
|
||||
|
||||
check_config(kSimpleStart, kSimpleStop);
|
||||
check_config(kSimpleStart, kConditionalStop);
|
||||
check_config(kConditionalStart, kSimpleStop);
|
||||
check_config(kConditionalStart, kConditionalStop);
|
||||
check_config(kSimpleStop);
|
||||
check_config(kConditionalStop);
|
||||
}
|
||||
|
||||
TEST_F(ConsumerTest, BatchSize) {
|
||||
@@ -252,7 +238,7 @@ TEST_F(ConsumerTest, BatchSize) {
|
||||
}
|
||||
std::this_thread::sleep_for(kBatchInterval * 2);
|
||||
consumer->Stop();
|
||||
EXPECT_TRUE(expected_messages_received) << "Some unexpected message have been received";
|
||||
EXPECT_TRUE(expected_messages_received) << "Some unexpected message has been received";
|
||||
|
||||
auto check_received_timestamp = [&received_timestamps](size_t index, size_t expected_message_count) {
|
||||
SCOPED_TRACE("Checking index " + std::to_string(index));
|
||||
@@ -371,7 +357,7 @@ TEST_F(ConsumerTest, DISABLED_StartsFromPreviousOffset) {
|
||||
EXPECT_EQ(expected_total_messages, received_message_count);
|
||||
EXPECT_NO_THROW(consumer->Stop());
|
||||
ASSERT_FALSE(consumer->IsRunning());
|
||||
EXPECT_TRUE(expected_messages_received) << "Some unexpected message have been received";
|
||||
EXPECT_TRUE(expected_messages_received) << "Some unexpected message has been received";
|
||||
};
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(send_and_consume_messages(2));
|
||||
@@ -383,10 +369,9 @@ TEST_F(ConsumerTest, CheckMethodWorks) {
|
||||
auto info = CreateDefaultConsumerInfo();
|
||||
info.batch_size = kBatchSize;
|
||||
const std::string kMessagePrefix{"Message"};
|
||||
auto consumer_function = [](const std::vector<Message> &messages) mutable {};
|
||||
|
||||
// This test depends on CreateConsumer starts and stops the consumer, so the offset is stored
|
||||
auto consumer = CreateConsumer(std::move(info), std::move(consumer_function));
|
||||
auto consumer = CreateConsumer(std::move(info), kDummyConsumerFunction);
|
||||
|
||||
static constexpr auto kMessageCount = 4;
|
||||
for (auto sent_messages = 0; sent_messages < kMessageCount; ++sent_messages) {
|
||||
@@ -411,7 +396,7 @@ TEST_F(ConsumerTest, CheckMethodWorks) {
|
||||
});
|
||||
ASSERT_FALSE(consumer->IsRunning());
|
||||
|
||||
EXPECT_TRUE(expected_messages_received) << "Some unexpected message have been received";
|
||||
EXPECT_TRUE(expected_messages_received) << "Some unexpected message has been received";
|
||||
EXPECT_EQ(received_message_count, kMessageCount);
|
||||
};
|
||||
|
||||
@@ -445,8 +430,6 @@ TEST_F(ConsumerTest, CheckWithInvalidTimeout) {
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
EXPECT_THROW(consumer.Check(std::chrono::milliseconds{0}, std::nullopt, kDummyConsumerFunction),
|
||||
ConsumerCheckFailedException);
|
||||
EXPECT_THROW(consumer.Check(std::chrono::milliseconds{-1}, std::nullopt, kDummyConsumerFunction),
|
||||
ConsumerCheckFailedException);
|
||||
const auto end = std::chrono::steady_clock::now();
|
||||
|
||||
static constexpr std::chrono::seconds kMaxExpectedTimeout{2};
|
||||
@@ -459,7 +442,6 @@ TEST_F(ConsumerTest, CheckWithInvalidBatchSize) {
|
||||
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
EXPECT_THROW(consumer.Check(std::nullopt, 0, kDummyConsumerFunction), ConsumerCheckFailedException);
|
||||
EXPECT_THROW(consumer.Check(std::nullopt, -1, kDummyConsumerFunction), ConsumerCheckFailedException);
|
||||
const auto end = std::chrono::steady_clock::now();
|
||||
|
||||
static constexpr std::chrono::seconds kMaxExpectedTimeout{2};
|
||||
@@ -496,8 +478,85 @@ TEST_F(ConsumerTest, ConsumerStatus) {
|
||||
check_info(consumer.Info());
|
||||
consumer.Start();
|
||||
check_info(consumer.Info());
|
||||
consumer.StartIfStopped();
|
||||
check_info(consumer.Info());
|
||||
consumer.StopIfRunning();
|
||||
check_info(consumer.Info());
|
||||
}
|
||||
|
||||
TEST_F(ConsumerTest, LimitBatches_CannotStartIfAlreadyRunning) {
|
||||
static constexpr auto kLimitBatches = 3;
|
||||
|
||||
auto info = CreateDefaultConsumerInfo();
|
||||
|
||||
auto consumer = CreateConsumer(std::move(info), kDummyConsumerFunction);
|
||||
|
||||
consumer->Start();
|
||||
ASSERT_TRUE(consumer->IsRunning());
|
||||
|
||||
EXPECT_THROW(consumer->StartWithLimit(kLimitBatches, std::nullopt /*timeout*/), ConsumerRunningException);
|
||||
|
||||
EXPECT_TRUE(consumer->IsRunning());
|
||||
|
||||
consumer->Stop();
|
||||
EXPECT_FALSE(consumer->IsRunning());
|
||||
}
|
||||
|
||||
TEST_F(ConsumerTest, LimitBatches_SendingMoreThanLimit) {
|
||||
/*
|
||||
We send more messages than the BatchSize*LimitBatches:
|
||||
-Consumer should receive 2*3=6 messages.
|
||||
-Consumer should not be running afterwards.
|
||||
*/
|
||||
static constexpr auto kBatchSize = 2;
|
||||
static constexpr auto kLimitBatches = 3;
|
||||
static constexpr auto kNumberOfMessagesToSend = 20;
|
||||
static constexpr auto kNumberOfMessagesExpected = kBatchSize * kLimitBatches;
|
||||
static constexpr auto kBatchInterval =
|
||||
std::chrono::seconds{2}; // We do not want the batch interval to be the limiting factor here.
|
||||
|
||||
auto info = CreateDefaultConsumerInfo();
|
||||
info.batch_size = kBatchSize;
|
||||
info.batch_interval = kBatchInterval;
|
||||
|
||||
static constexpr std::string_view kMessage = "LimitBatchesTestMessage";
|
||||
|
||||
auto expected_messages_received = true;
|
||||
auto number_of_messages_received = 0;
|
||||
auto consumer_function = [&expected_messages_received,
|
||||
&number_of_messages_received](const std::vector<Message> &messages) mutable {
|
||||
number_of_messages_received += messages.size();
|
||||
for (const auto &message : messages) {
|
||||
expected_messages_received &= (kMessage == std::string_view(message.Payload().data(), message.Payload().size()));
|
||||
}
|
||||
};
|
||||
|
||||
auto consumer = CreateConsumer(std::move(info), consumer_function);
|
||||
|
||||
for (auto sent_messages = 0; sent_messages <= kNumberOfMessagesToSend; ++sent_messages) {
|
||||
cluster.SeedTopic(kTopicName, kMessage);
|
||||
}
|
||||
|
||||
consumer->StartWithLimit(kLimitBatches, kDontCareTimeout);
|
||||
|
||||
EXPECT_FALSE(consumer->IsRunning());
|
||||
EXPECT_EQ(number_of_messages_received, kNumberOfMessagesExpected);
|
||||
EXPECT_TRUE(expected_messages_received) << "Some unexpected message has been received";
|
||||
}
|
||||
|
||||
TEST_F(ConsumerTest, LimitBatches_Timeout_Reached) {
|
||||
// We do not send any messages, we expect an exeption to be thrown.
|
||||
static constexpr auto kLimitBatches = 3;
|
||||
|
||||
auto info = CreateDefaultConsumerInfo();
|
||||
|
||||
auto consumer = CreateConsumer(std::move(info), kDummyConsumerFunction);
|
||||
|
||||
std::chrono::milliseconds timeout{3000};
|
||||
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
EXPECT_THROW(consumer->StartWithLimit(kLimitBatches, timeout), ConsumerStartFailedException);
|
||||
const auto end = std::chrono::steady_clock::now();
|
||||
const auto elapsed = (end - start);
|
||||
|
||||
EXPECT_LE(timeout, elapsed);
|
||||
EXPECT_LE(elapsed, timeout * 1.2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user