Files
letta-server/tests/test_plugins.py
Kian Jones 82495b68a3 chore(ci): Add uv support and use for unit tests (#4127)
* cherrypick just relevant commits?

* make work with poetry

* update poetry?

* regen?

* change tests and dev to dependency groups instead of optional extras

* Fix Poetry/UV compatibility issues

- Fix sqlite-vec dependency: Remove optional flag from Poetry section to match main deps
- Regenerate poetry.lock to sync with pyproject.toml changes
- Test both package managers successfully:
  - Poetry: `poetry install --with dev --with test -E postgres -E external-tools -E cloud-tool-sandbox`
  - UV: `uv sync --group dev --group test --extra postgres --extra external-tools --extra cloud-tool-sandbox`

Resolves Poetry lock sync errors and ensures sqlite-vec is available for tests.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* more robust pip install

* Fix fern SDK wheel installation in CI workflow

Replace unreliable command substitution with proper error handling:
- Check if directory exists before attempting to find wheels
- Store wheel file path in variable to avoid empty arguments
- Provide clear error messages when directory/wheels are missing
- Prevents "required arguments were not provided" error in uv pip install

Fixes: error: the following required arguments were not provided: <PACKAGE>

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* debugging

* trigger CI

* ls

* revert whl installation to -e

* programmatic HIT version insertion

* version templating properly

* set var properly

* labelling

* remove version insertion

* ?

* try using sed '2r /dev/stdin'

* version

* try again smh

* not trigger on poetry version

* only add once

* filter only for project not poetry

* hand re-construct the file

* save tail?

* fix docker command

* please please please

* rename test -> tests

* update poetry and rename group to -E

* move async into tests extra and regen lock files and add sqlite extra

* remove loading cached venv from cloud api integration

* add uv dependency to CI runners

* test removing the custom event loop

* regen poetry.lock and try to fix async tests

* wrap async pg exception and event loop tweak in plugins

* remove event loop from plugins test and remove caching from cloud-api-integration-test

* migrate all tests away from event loop for pytest-asyncio

* pin firecrawl

* pin e2b

* take claude's suggestion

* deeper down the claude rabbit hole

* increase timeout for httpbin.org

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-26 11:51:31 -07:00

97 lines
3.4 KiB
Python

import pytest
from letta.data_sources.redis_client import NoopAsyncRedisClient, get_redis_client
from letta.helpers.decorators import experimental
from letta.settings import settings
@pytest.mark.asyncio
async def test_default_experimental_decorator():
settings.plugin_register = "experimental_check=tests.helpers.plugins_helper:is_experimental_okay"
@experimental("test_just_pass", fallback_function=lambda: False, kwarg1=3)
def _return_true():
return True
assert _return_true()
settings.plugin_register = ""
@pytest.mark.asyncio
async def test_overwrite_arg_success():
settings.plugin_register = "experimental_check=tests.helpers.plugins_helper:is_experimental_okay"
@experimental("test_override_kwarg", fallback_function=lambda *args, **kwargs: False, bool_val=True)
async def _return_true(a_val: bool, bool_val: bool):
assert bool_val is False
return True
assert _return_true(False, False)
settings.plugin_register = ""
@pytest.mark.asyncio
async def test_overwrite_arg_fail():
# Should fallback to lambda
settings.plugin_register = "experimental_check=tests.helpers.plugins_helper:is_experimental_okay"
@experimental("test_override_kwarg", fallback_function=lambda *args, **kwargs: True, bool_val=False)
async def _return_false(a_val: bool, bool_val: bool):
assert bool_val is True
return False
assert _return_false(False, True)
@experimental("test_override_kwarg", fallback_function=lambda *args, **kwargs: False, bool_val=True)
async def _return_true(a_val: bool, bool_val: bool):
assert bool_val is False
return True
assert _return_true(False, bool_val=False)
@experimental("test_override_kwarg", fallback_function=lambda *args, **kwargs: True)
async def _get_true(a_val: bool, bool_val: bool):
return True
assert await _get_true(True, bool_val=True)
with pytest.raises(Exception):
# kwarg must be included in either experimental flag or function call
assert await _get_true(True, True)
settings.plugin_register = ""
@pytest.mark.asyncio
async def test_redis_flag():
settings.plugin_register = "experimental_check=tests.helpers.plugins_helper:is_experimental_okay"
@experimental("test_redis_flag", fallback_function=lambda *args, **kwargs: _raise())
async def _new_feature(user_id: str) -> str:
return "new_feature"
def _raise():
raise Exception()
redis_client = await get_redis_client()
group_name = "TEST_GROUP"
include_key = redis_client._get_group_inclusion_key(group_name)
exclude_key = redis_client._get_group_exclusion_key(group_name)
test_user = "user123"
# reset
for member in await redis_client.smembers(include_key):
await redis_client.srem(include_key, member)
for member in await redis_client.smembers(exclude_key):
await redis_client.srem(exclude_key, member)
await redis_client.create_inclusion_exclusion_keys(group=group_name)
await redis_client.sadd(include_key, test_user)
if not isinstance(redis_client, NoopAsyncRedisClient):
assert await _new_feature(user_id=test_user) == "new_feature"
with pytest.raises(Exception):
await _new_feature(user_id=test_user + "1")
print("members: ", await redis_client.smembers(include_key))
else:
with pytest.raises(Exception):
await _new_feature(user_id=test_user)