Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d635d5a
feat: add chat test parity with stream-chat-python
Mar 2, 2026
41a813f
chore: regenerate SDK from latest OpenAPI spec
Mar 2, 2026
84f7c26
fix: fix test failures to match actual API responses
Mar 2, 2026
61e4d48
fix: correct skip reasons after investigating backend behavior
Mar 2, 2026
064c70e
fix: fix test_delete_message_for_me - add user as channel member
Mar 2, 2026
bc791a0
fix: fix test_query_message_flags to match getstream-go approach
Mar 2, 2026
9689bd2
feat: match chat test parity with getstream-go and split CI credentials
Mar 2, 2026
f195524
fix: add STREAM_CHAT_BASE_URL for non-video CI tests
Mar 2, 2026
c16166e
fix: properly separate video and non-video tests in CI
Mar 2, 2026
3c0ac3d
fix: fix test_delete_channels timeout and wait_for_task
Mar 2, 2026
77c45ff
style: fix ruff formatting in tests/base.py
Mar 2, 2026
c895a8e
refactor: reorganize test_chat_channel.py per code review feedback
Mar 2, 2026
e1c88c8
fix: address code review feedback in test_chat_message and test_chat_…
Mar 2, 2026
f55b775
fix: extract command names as strings when restoring channel type config
Mar 2, 2026
ead8884
test: add missing chat tests for parity with stream-chat-python
Mar 2, 2026
bd26026
test: add missing chat tests for parity with stream-chat-python
Mar 3, 2026
d354b1d
fix: raise RuntimeError on task failure in wait_for_task
Mar 3, 2026
6b3ee8d
test: skip test_permissions_roles (slow and flaky)
Mar 3, 2026
bd45c2e
fix: restore video directory doctests in CI coverage
Mar 3, 2026
fd48932
ci: make step-level credentials explicit, remove redundant job-level env
Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 27 additions & 10 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,6 @@ jobs:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
env:
STREAM_BASE_URL: ${{ vars.STREAM_BASE_URL }}
STREAM_API_KEY: ${{ vars.STREAM_API_KEY }}
STREAM_API_SECRET: ${{ secrets.STREAM_API_SECRET }}
timeout-minutes: 30
steps:
- name: Checkout
Expand All @@ -81,11 +77,32 @@ jobs:
uses: ./.github/actions/python-uv-setup
with:
python-version: ${{ matrix.python-version }}
- name: Debug environment variables
- name: Run non-video tests
env:
STREAM_API_KEY: ${{ vars.STREAM_CHAT_API_KEY }}
STREAM_API_SECRET: ${{ secrets.STREAM_CHAT_API_SECRET }}
STREAM_BASE_URL: ${{ vars.STREAM_CHAT_BASE_URL }}
run: |
echo "STREAM_API_KEY is set: ${{ env.STREAM_API_KEY != '' }}"
echo "STREAM_API_SECRET is set: ${{ env.STREAM_API_SECRET != '' }}"
echo "STREAM_BASE_URL is set: ${{ env.STREAM_BASE_URL != '' }}"
- name: Run tests
run: uv run pytest -m "${{ inputs.marker }}" tests/ getstream/
uv run pytest -m "${{ inputs.marker }}" tests/ getstream/ \
--ignore=tests/rtc \
--ignore=tests/test_video_examples.py \
--ignore=tests/test_video_integration.py \
--ignore=tests/test_video_openai.py \
--ignore=tests/test_signaling.py \
--ignore=tests/test_audio_stream_track.py \
--ignore=getstream/video
- name: Run video tests
env:
STREAM_API_KEY: ${{ vars.STREAM_API_KEY }}
STREAM_API_SECRET: ${{ secrets.STREAM_API_SECRET }}
STREAM_BASE_URL: ${{ vars.STREAM_BASE_URL }}
run: |
uv run pytest -m "${{ inputs.marker }}" \
tests/rtc \
tests/test_video_examples.py \
tests/test_video_integration.py \
tests/test_video_openai.py \
tests/test_signaling.py \
tests/test_audio_stream_track.py \
getstream/video

8 changes: 7 additions & 1 deletion getstream/feeds/rest_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -725,13 +725,19 @@ def add_comments_batch(
def query_comments(
self,
filter: Dict[str, object],
id_around: Optional[str] = None,
limit: Optional[int] = None,
next: Optional[str] = None,
prev: Optional[str] = None,
sort: Optional[str] = None,
) -> StreamResponse[QueryCommentsResponse]:
json = QueryCommentsRequest(
filter=filter, limit=limit, next=next, prev=prev, sort=sort
filter=filter,
id_around=id_around,
limit=limit,
next=next,
prev=prev,
sort=sort,
).to_dict()
return self.post(
"/api/v2/feeds/comments/query", QueryCommentsResponse, json=json
Expand Down
6 changes: 5 additions & 1 deletion getstream/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1787,7 +1787,8 @@ class AsyncExportErrorEvent(DataClassJsonMixin):
task_id: str = dc_field(metadata=dc_config(field_name="task_id"))
custom: Dict[str, object] = dc_field(metadata=dc_config(field_name="custom"))
type: str = dc_field(
default="export.moderation_logs.error", metadata=dc_config(field_name="type")
default="export.bulk_image_moderation.error",
metadata=dc_config(field_name="type"),
)
received_at: Optional[datetime] = dc_field(
default=None,
Expand Down Expand Up @@ -16024,6 +16025,9 @@ class QueryCommentReactionsResponse(DataClassJsonMixin):
@dataclass
class QueryCommentsRequest(DataClassJsonMixin):
filter: Dict[str, object] = dc_field(metadata=dc_config(field_name="filter"))
id_around: Optional[str] = dc_field(
default=None, metadata=dc_config(field_name="id_around")
)
limit: Optional[int] = dc_field(
default=None, metadata=dc_config(field_name="limit")
)
Expand Down
Binary file added tests/assets/test_upload.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions tests/assets/test_upload.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello world test file content
11 changes: 6 additions & 5 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,23 @@ def wait_for_task(client, task_id, timeout_ms=10000, poll_interval_ms=1000):
Args:
client: The client used to make the API call.
task_id: The ID of the task to wait for.
timeout: The maximum amount of time to wait (in ms).
poll_interval: The interval between poll attempts (in ms).
timeout_ms: The maximum amount of time to wait (in ms).
poll_interval_ms: The interval between poll attempts (in ms).

Returns:
The final response from the API.

Raises:
RuntimeError: If the task failed.
TimeoutError: If the task is not completed within the timeout period.
"""
start_time = time.time() * 1000 # Convert to milliseconds
while True:
response = client.get_task(id=task_id)
if response.data.status == "completed":
return response
if response.data.status == "failed":
raise RuntimeError(f"Task {task_id} failed")
if (time.time() * 1000) - start_time > timeout_ms:
raise TimeoutError(
f"Task {task_id} did not complete within {timeout_ms} seconds"
)
raise TimeoutError(f"Task {task_id} did not complete within {timeout_ms}ms")
time.sleep(poll_interval_ms / 1000.0)
75 changes: 75 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import functools
import uuid
import pytest
import os
from dotenv import load_dotenv
Expand All @@ -12,6 +13,9 @@
async_client,
)

from getstream import Stream
from getstream.models import UserRequest, ChannelInput

__all__ = [
"client",
"call",
Expand All @@ -20,9 +24,80 @@
"test_feed",
"get_feed",
"async_client",
"channel",
"random_user",
"random_users",
"server_user",
]


@pytest.fixture
def random_user(client: Stream):
user_id = str(uuid.uuid4())
response = client.update_users(
users={user_id: UserRequest(id=user_id, name=user_id)}
)
assert user_id in response.data.users
yield response.data.users[user_id]
try:
client.delete_users(
user_ids=[user_id], user="hard", conversations="hard", messages="hard"
)
except Exception:
pass


@pytest.fixture
def random_users(client: Stream):
users = []
user_ids = []
for _ in range(3):
uid = str(uuid.uuid4())
user_ids.append(uid)
users.append(UserRequest(id=uid, name=uid))
response = client.update_users(users={u.id: u for u in users})
yield [response.data.users[uid] for uid in user_ids]
try:
client.delete_users(
user_ids=user_ids, user="hard", conversations="hard", messages="hard"
)
except Exception:
pass


@pytest.fixture
def server_user(client: Stream):
user_id = str(uuid.uuid4())
response = client.update_users(
users={user_id: UserRequest(id=user_id, name="server-admin")}
)
assert user_id in response.data.users
yield response.data.users[user_id]
try:
client.delete_users(
user_ids=[user_id], user="hard", conversations="hard", messages="hard"
)
except Exception:
pass


@pytest.fixture
def channel(client: Stream, random_user):
channel_id = str(uuid.uuid4())
ch = client.chat.channel("messaging", channel_id)
ch.get_or_create(
data=ChannelInput(
created_by_id=random_user.id,
custom={"test": True, "language": "python"},
)
)
yield ch
try:
client.chat.delete_channels(cids=[f"messaging:{channel_id}"], hard_delete=True)
except Exception:
pass


@pytest.fixture(scope="session", autouse=True)
def load_env():
load_dotenv()
Expand Down
Loading