Skip to content

Commit 454feb6

Browse files
committed
CAIP-80 feed test is added
1 parent c3e0131 commit 454feb6

4 files changed

Lines changed: 211 additions & 85 deletions

File tree

.github/workflows/build.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,12 @@ jobs:
5656
- name: Run tests with coverage
5757
env:
5858
TEST_RSA_KEY: ${{ secrets.TEST_RSA_KEY }}
59-
BOT_USERNAME: ${{ vars.BOT_USERNAME }}
59+
MSG_BOT_USERNAME: ${{ vars.MSG_BOT_USERNAME }}
60+
FEED_BOT_USERNAME: ${{ vars.FEED_BOT_USERNAME }}
6061
STREAM_ID: ${{ vars.STREAM_ID }}
6162
SYMPHONY_HOST: ${{ vars.SYMPHONY_HOST }}
63+
TEST_USER_ID: ${{ vars.TEST_SYM_USER_ID }}
64+
BOT_USER_ID: ${{ vars.BOT_USER_ID }}
6265
run: poetry run pytest
6366
timeout-minutes: 10
6467

tests/bdk/integration/e2e_test.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import asyncio
2+
from datetime import datetime, timedelta
3+
from uuid import uuid4
4+
5+
import pytest
6+
import pytest_asyncio
7+
8+
from symphony.bdk.core.config.loader import BdkConfigLoader
9+
from symphony.bdk.core.symphony_bdk import SymphonyBdk
10+
from symphony.bdk.gen.pod_model.v3_room_attributes import V3RoomAttributes
11+
from tests.bdk.integration.helpers import (BOT_USER_ID, FEED_BOT_USERNAME,
12+
MSG_BOT_USERNAME, STREAM_ID,
13+
SYMPHONY_HOST, TEST_RSA_KEY,
14+
TEST_USER_ID, MessageListener,
15+
datafeed_bot_config,
16+
get_test_messages,
17+
messenger_bot_config, send_messages)
18+
19+
pytestmark = pytest.mark.asyncio
20+
21+
22+
pytestmark = pytest.mark.skipif(
23+
not all(
24+
[
25+
STREAM_ID,
26+
MSG_BOT_USERNAME,
27+
FEED_BOT_USERNAME,
28+
SYMPHONY_HOST,
29+
TEST_RSA_KEY,
30+
TEST_USER_ID,
31+
BOT_USER_ID,
32+
]
33+
),
34+
reason="Required environment variables for integration tests are not set "
35+
"(STREAM_ID, MSG_BOT_USERNAME, FEED_BOT_USERNAME, SYMPHONY_HOST, TEST_RSA_KEY, TEST_USER_ID, BOT_USER_ID)",
36+
)
37+
38+
NUMBER_OF_MESSAGES = 3
39+
40+
41+
@pytest_asyncio.fixture
42+
async def bdk(messenger_bot_config):
43+
config = BdkConfigLoader.load_from_file(str(messenger_bot_config))
44+
async with SymphonyBdk(config) as bdk:
45+
yield bdk
46+
47+
48+
@pytest.mark.asyncio
49+
async def test_bot_read_write_messages(bdk):
50+
uuid = str(uuid4())
51+
# Given: test execution start time
52+
since = int((datetime.now() - timedelta(seconds=2)).timestamp()) * 1000
53+
# Given: BDK is initialized with config
54+
# When: messages are sent via bot
55+
await send_messages(bdk.messages(), STREAM_ID, since, uuid)
56+
# Then: messages are readable with the same bot
57+
messages = await get_test_messages(bdk, since, uuid)
58+
# Then: Expected messages are posted to the room
59+
assert sorted(messages) == [
60+
f"{uuid}-{i}-{since}" for i in range(NUMBER_OF_MESSAGES)
61+
]
62+
63+
64+
@pytest.mark.asyncio
65+
async def test_bot_creates_stream_add_delete_user(bdk):
66+
test_user = int(TEST_USER_ID)
67+
# Given: Stream bdk creates a room
68+
streams = bdk.streams()
69+
room_result = await streams.create_room(
70+
V3RoomAttributes(name="New fancy room", description="test room")
71+
)
72+
room_id = room_result.room_system_info.id
73+
# When: user is added to the room
74+
await streams.add_member_to_room(test_user, room_id)
75+
members = await streams.list_room_members(room_id)
76+
# Then: user is present in the room
77+
assert test_user in [m.id for m in members.value]
78+
# When: user is removed from the room
79+
await streams.remove_member_from_room(test_user, room_id)
80+
# Then: user is deleted from the room
81+
members_after_removal = await streams.list_room_members(room_id)
82+
assert test_user not in [m.id for m in members_after_removal.value]
83+
84+
85+
@pytest.mark.asyncio
86+
async def test_datafeed_receives_message(bdk: SymphonyBdk, datafeed_bot_config):
87+
"""
88+
Test is running 2 bdk instances at the same time.
89+
Data feed filters its own events so in order to see that feed is working
90+
Two parale bots are added
91+
92+
"""
93+
# Given: message listener is initialized with expected message id
94+
unique_id = str(uuid4())
95+
message_content = f"Message for datafeed test. ID: {unique_id}"
96+
listener = MessageListener(message_to_find=message_content)
97+
# Given: members are added to the room
98+
bdk.datafeed().subscribe(listener)
99+
await bdk.streams().add_member_to_room(int(BOT_USER_ID), STREAM_ID)
100+
datafeed_task = asyncio.create_task(bdk.datafeed().start())
101+
await asyncio.sleep(3)
102+
config = BdkConfigLoader.load_from_file(str(datafeed_bot_config))
103+
async with SymphonyBdk(config) as another_bot:
104+
# When: another bot instance sends a message to the needed room
105+
await another_bot.messages().send_message(STREAM_ID, message_content)
106+
try:
107+
# Then: particular message is received by datafeed instance
108+
await asyncio.wait_for(listener.message_received_event.wait(), timeout=30)
109+
except asyncio.TimeoutError:
110+
pytest.fail("Datafeed did not receive the message within the timeout period.")
111+
finally:
112+
await bdk.datafeed().stop()
113+
await datafeed_task
114+
bdk.datafeed().unsubscribe(listener)
115+
116+
assert listener.message_received_event.is_set()

tests/bdk/integration/helpers.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import asyncio
2+
import os
3+
import re
4+
5+
import pytest
6+
import pytest_asyncio
7+
import yaml
8+
9+
from symphony.bdk.core.config.loader import BdkConfigLoader
10+
from symphony.bdk.core.service.datafeed.real_time_event_listener import \
11+
RealTimeEventListener
12+
from symphony.bdk.core.symphony_bdk import SymphonyBdk
13+
from symphony.bdk.gen.agent_model.v4_initiator import V4Initiator
14+
from symphony.bdk.gen.agent_model.v4_message_sent import V4MessageSent
15+
16+
STREAM_ID = os.getenv("STREAM_ID")
17+
MSG_BOT_USERNAME = os.getenv("MSG_BOT_USERNAME")
18+
FEED_BOT_USERNAME = os.getenv("FEED_BOT_USERNAME")
19+
SYMPHONY_HOST = os.getenv("SYMPHONY_HOST")
20+
TEST_RSA_KEY = os.getenv("TEST_RSA_KEY")
21+
TEST_USER_ID = os.getenv("TEST_USER_ID")
22+
BOT_USER_ID = os.getenv("BOT_USER_ID")
23+
NUMBER_OF_MESSAGES = 3
24+
25+
26+
def generate_config(tmp_dir, bot_username):
27+
key_path = tmp_dir / "key.pem"
28+
config_path = tmp_dir / "config.yaml"
29+
30+
bot_config_dict = {
31+
"host": SYMPHONY_HOST,
32+
"bot": {"username": bot_username, "privateKey": {"path": str(key_path)}},
33+
}
34+
35+
key_path.write_text(TEST_RSA_KEY)
36+
with config_path.open("w") as config_file:
37+
yaml.dump(bot_config_dict, config_file)
38+
39+
return config_path
40+
41+
42+
@pytest.fixture
43+
def messenger_bot_config(tmp_path_factory):
44+
tmp_dir = tmp_path_factory.mktemp("bdk_config_messenger")
45+
return generate_config(tmp_dir, MSG_BOT_USERNAME)
46+
47+
48+
@pytest.fixture
49+
def datafeed_bot_config(tmp_path_factory):
50+
tmp_dir = tmp_path_factory.mktemp("bdk_config_feed")
51+
return generate_config(tmp_dir, FEED_BOT_USERNAME)
52+
53+
54+
@pytest_asyncio.fixture
55+
async def bdk(messenger_bot_config):
56+
config = BdkConfigLoader.load_from_file(str(messenger_bot_config))
57+
async with SymphonyBdk(config) as bdk:
58+
yield bdk
59+
60+
61+
async def send_messages(messages, stream_id, since, uuid):
62+
for i in range(NUMBER_OF_MESSAGES):
63+
await messages.send_message(
64+
stream_id, f"<messageML><b>{uuid}-{i}-{since}</b></messageML>"
65+
)
66+
67+
68+
async def get_test_messages(bdk, since, uuid):
69+
messages = await bdk.messages().list_messages(STREAM_ID, since=since)
70+
cleaned_messages_text = [
71+
re.sub(r"<[^>]+>", " ", msg["message"]).strip() for msg in messages
72+
]
73+
return list(
74+
filter(
75+
lambda msg: msg.startswith(uuid),
76+
cleaned_messages_text,
77+
)
78+
)
79+
80+
81+
class MessageListener(RealTimeEventListener):
82+
"""A simple listener to capture a specific message from the datafeed."""
83+
84+
def __init__(self, message_to_find: str):
85+
self._message_to_find = message_to_find
86+
self.message_received_event = asyncio.Event()
87+
88+
async def on_message_sent(self, initiator: V4Initiator, event: V4MessageSent):
89+
message_text = re.sub(r"<[^>]+>", "", event.message.message).strip()
90+
if self._message_to_find in message_text:
91+
self.message_received_event.set()

tests/bdk/integration/test_post_message.py

Lines changed: 0 additions & 84 deletions
This file was deleted.

0 commit comments

Comments
 (0)