diff --git a/tests/unit_tests/core/test_bootutils_deps.py b/tests/unit_tests/core/test_bootutils_deps.py index 13fa156d7..c93604a07 100644 --- a/tests/unit_tests/core/test_bootutils_deps.py +++ b/tests/unit_tests/core/test_bootutils_deps.py @@ -50,8 +50,7 @@ class TestCheckDeps: result = asyncio.run(check_deps()) - assert 'requests' in result - assert 'openai' in result + assert result == ['requests', 'openai'] def test_check_deps_all_missing(self): """check_deps returns all deps when none present.""" @@ -66,8 +65,7 @@ class TestCheckDeps: result = asyncio.run(check_deps()) - # Should include all required_deps keys - assert len(result) == len(required_deps) + assert result == list(required_deps) def test_required_deps_dict_exists(self): """required_deps dictionary is defined.""" diff --git a/tests/unit_tests/core/test_load_config.py b/tests/unit_tests/core/test_load_config.py index 051597875..b24a36b8f 100644 --- a/tests/unit_tests/core/test_load_config.py +++ b/tests/unit_tests/core/test_load_config.py @@ -119,12 +119,11 @@ class TestApplyEnvOverridesToConfig: """Test that '1', 'yes', 'on' are treated as true.""" load_config = get_load_config_module() - cfg = {'system': {'flag': False}} - for true_val in ['1', 'yes', 'on', 'TRUE']: + cfg = {'system': {'flag': False}} env = {'SYSTEM__FLAG': true_val} with patch.dict(os.environ, env, clear=True): - result = load_config._apply_env_overrides_to_config(cfg.copy()) + result = load_config._apply_env_overrides_to_config(cfg) assert result['system']['flag'] is True def test_override_float_value(self): @@ -237,7 +236,7 @@ class TestApplyEnvOverridesToConfig: with patch.dict(os.environ, env, clear=True): result = load_config._apply_env_overrides_to_config(cfg) - assert result['system']['name'] == 'default' + assert result == {'system': {'name': 'default'}} def test_skip_env_vars_with_empty_path_segments(self, capsys): """Platform variables such as __CF_USER_TEXT_ENCODING are not config.""" @@ -249,7 +248,7 @@ class TestApplyEnvOverridesToConfig: with patch.dict(os.environ, env, clear=True): result = load_config._apply_env_overrides_to_config(cfg) - assert result == cfg + assert result == {'system': {'name': 'default'}} assert capsys.readouterr().out == '' def test_nested_config_path(self): @@ -299,7 +298,7 @@ class TestApplyEnvOverridesToConfig: with patch.dict(os.environ, env, clear=True): result = load_config._apply_env_overrides_to_config(cfg) - assert result == cfg + assert result == {'system': {'name': 'default'}} def test_multiple_env_vars_override(self): """Test multiple env vars applied in order.""" diff --git a/tests/unit_tests/core/test_taskmgr.py b/tests/unit_tests/core/test_taskmgr.py index 3477478bb..85d1657bb 100644 --- a/tests/unit_tests/core/test_taskmgr.py +++ b/tests/unit_tests/core/test_taskmgr.py @@ -15,7 +15,7 @@ import asyncio import contextvars import inspect import sys -from unittest.mock import Mock, MagicMock +from unittest.mock import Mock, MagicMock, patch from contextlib import contextmanager from typing import Generator @@ -181,12 +181,14 @@ class TestTaskContext: ctx.set_current_action('test_action') ctx.trace('Test message') ctx.metadata['key'] = 'value' + ctx.metadata['count'] = 5 + ctx.metadata['items'] = ['a', 'b', 'c'] result = ctx.to_dict() assert result['current_action'] == 'test_action' assert 'Test message' in result['log'] - assert result['metadata'] == {'key': 'value'} + assert result['metadata'] == {'key': 'value', 'count': 5, 'items': ['a', 'b', 'c']} def test_static_new_factory(self): """Test TaskContext.new() factory method.""" @@ -209,19 +211,9 @@ class TestTaskContext: ctx1 = TaskContext.placeholder() ctx2 = TaskContext.placeholder() + assert isinstance(ctx1, TaskContext) assert ctx1 is ctx2 - def test_metadata_is_mutable_dict(self): - """Test that metadata is a mutable dict.""" - TaskContext, _, _ = get_taskmgr_classes() - ctx = TaskContext() - - ctx.metadata['count'] = 5 - ctx.metadata['items'] = ['a', 'b', 'c'] - - assert ctx.metadata['count'] == 5 - assert len(ctx.metadata['items']) == 3 - class TestTaskWrapper: """Tests for TaskWrapper class.""" @@ -346,7 +338,8 @@ class TestTaskWrapper: async def successful_coro(): return {'file_id': 'file-a'} - wrapper = TaskWrapper(mock_app, successful_coro(), kind='knowledge_base.store') + with patch('time.time', return_value=1720000000.25): + wrapper = TaskWrapper(mock_app, successful_coro(), kind='knowledge_base.store') await wrapper.task result = wrapper.to_public_dict() @@ -358,7 +351,7 @@ class TestTaskWrapper: 'status': 'succeeded', 'error': None, 'result': {'file_id': 'file-a'}, - 'created_at': result['created_at'], + 'created_at': 1720000000.25, } assert 'runtime' not in result assert 'traceback' not in str(result).lower() @@ -429,6 +422,29 @@ class TestTaskWrapper: class TestAsyncTaskManager: """Tests for AsyncTaskManager class.""" + @pytest.mark.asyncio + async def test_completed_retention_keeps_newest_tasks_and_running_task(self): + _, _, AsyncTaskManager = get_taskmgr_classes() + mock_app = create_mock_app() + mock_app.instance_config.data['system']['task_retention']['completed_limit'] = 2 + manager = AsyncTaskManager(mock_app) + running = manager.create_task(asyncio.Event().wait()) + + async def immediate_coro(): + return 'done' + + try: + completed = [manager.create_task(immediate_coro()) for _ in range(2)] + await asyncio.gather(*(wrapper.task for wrapper in completed)) + assert manager.tasks == [running, *completed] + + newest = manager.create_task(immediate_coro()) + await newest.task + assert manager.tasks == [running, completed[1], newest] + finally: + running.cancel() + await asyncio.gather(running.task, return_exceptions=True) + @pytest.mark.asyncio async def test_create_task_adds_to_list(self): """Test that create_task adds task to tasks list."""