Skip to content

test(core): increase tool_registry coverage from 47% to 69%#6818

Merged
Hundao merged 3 commits into
aden-hive:mainfrom
raiigauravv:test/tool-registry-coverage
Apr 1, 2026
Merged

test(core): increase tool_registry coverage from 47% to 69%#6818
Hundao merged 3 commits into
aden-hive:mainfrom
raiigauravv:test/tool-registry-coverage

Conversation

@raiigauravv

@raiigauravv raiigauravv commented Mar 26, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds 19 new unit tests for ToolRegistry in core/tests/test_tool_registry.py, increasing branch coverage from 47% to 69% (+22 pp).

What's covered

Category Tests Added
register_function() Type hint → JSON schema, required vs optional, name/description overrides, docstring fallback, executor delegation
@tool decorator discovery discover_from_module() picks up @tool-decorated functions
Module discovery edge cases Missing file → 0; TOOLS without tool_executor → mock executor
has_tool() / get_registered_names() True/False checks, multi-tool listing
Session context injection MCP call receives workspace_id/agent_id from set_session_context()
Execution context override set_execution_context() wins over session context via contextvars
_convert_mcp_tool_to_framework_tool() Strips CONTEXT_PARAMS from LLM schema properties and required list
load_mcp_config() List format, dict format, graceful invalid-JSON warning
resync_mcp_servers_if_needed() Returns False with no clients; returns False when nothing changed

Test results

31 passed in 3.54s

Name                                     Stmts   Miss  Cover
------------------------------------------------------------
core/framework/runner/tool_registry.py     392    123    69%
------------------------------------------------------------

Ruff: ✅ All checks passed

Relates to #1972
Fix #1972

Summary by CodeRabbit

  • Tests
    • Expanded coverage for tool registration: parameter type inference, required vs optional, name/description overrides, and executor return behavior
    • Added discovery and registry query tests (tool discovery, has_tool, get_registered_names)
    • MCP integration tests for session/context injection and precedence of execution-context values
    • Schema conversion tests to strip context-only fields
    • Config-loading and resync tests, including multiple server formats, invalid-JSON warnings, and resync no-op checks

Add 19 new tests covering previously untested paths in ToolRegistry:

- register_function: type hint inference (int/float/bool/dict/list),
  required vs optional params, custom name/description, docstring fallback,
  executor delegation
- discover_from_module: @tool decorator pickup, missing-file zero-count,
  TOOLS dict without tool_executor uses mock executor
- has_tool / get_registered_names basic assertions
- Session context injection into MCP tool calls via set_session_context()
- Execution context override (contextvars) wins over session context
- _convert_mcp_tool_to_framework_tool: strips CONTEXT_PARAMS from both
  properties and required lists
- load_mcp_config: list format, dict format, graceful invalid-JSON warning
- resync_mcp_servers_if_needed: returns False with no clients; returns
  False when credentials and ADEN_API_KEY are unchanged

Coverage: 47 % → 69 % (+22 pp), all 31 tests pass, ruff clean.

Relates to aden-hive#1972
@github-actions

Copy link
Copy Markdown

PR Requirements Warning

This PR does not meet the contribution requirements.
If the issue is not fixed within ~24 hours, it may be automatically closed.

PR Author: @raiigauravv
Found issues: #1972 (assignees: AasthaParmar)
Problem: The PR author must be assigned to the linked issue.

To fix:

  1. Assign yourself (@raiigauravv) to one of the linked issues
  2. Re-open this PR

Exception: To bypass this requirement, you can:

  • Add the micro-fix label or include micro-fix in your PR title for trivial fixes
  • Add the documentation label or include doc/docs in your PR title for documentation changes

Micro-fix requirements (must meet ALL):

Qualifies Disqualifies
< 20 lines changed Any functional bug fix
Typos & Documentation & Linting Refactoring for "clean code"
No logic/API/DB changes New features (even tiny ones)

Why is this required? See #472 for details.

@github-actions github-actions Bot added the pr-requirements-warning PR doesn't follow contribution guidelines. Please fix or it will be auto-closed. label Mar 26, 2026
@raiigauravv

Copy link
Copy Markdown
Contributor Author

Flagging for maintainer attention — PR #2028 (the other test coverage PR for #1972) has unresolved merge conflicts and has been stale since Jan 31. This PR is conflict-free, passes all 31 tests, ruff clean, and brings coverage from 47% → 69% (+22pp). Tagging @Hundao for review.

@github-actions

Copy link
Copy Markdown

Closing PR because the contribution requirements were not resolved within the 24-hour grace period.
If this was closed in error, feel free to reopen the PR after fixing the requirements.

@github-actions github-actions Bot closed this Mar 28, 2026
@Hundao Hundao reopened this Mar 28, 2026
@github-actions github-actions Bot removed the pr-requirements-warning PR doesn't follow contribution guidelines. Please fix or it will be auto-closed. label Mar 28, 2026
@coderabbitai

coderabbitai Bot commented Apr 1, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f3508f1d-fd13-42a1-b7a9-b147c3727c53

📥 Commits

Reviewing files that changed from the base of the PR and between 4a01c7f and a9728ca.

📒 Files selected for processing (1)
  • core/tests/test_tool_registry.py
✅ Files skipped from review due to trivial changes (1)
  • core/tests/test_tool_registry.py

📝 Walkthrough

Walkthrough

Added a comprehensive test suite for ToolRegistry, introducing ~404 lines of tests that validate function registration, type-to-JSON-schema inference, module discovery, registry queries, MCP integration and conversion, MCP config loading, and resync behavior.

Changes

Cohort / File(s) Summary
ToolRegistry Test Suite
core/tests/test_tool_registry.py
Added ~404 lines of tests covering: register_function behavior (annotation→JSON-schema mapping; required vs optional params; name/description overrides; executor result), discover_from_module and @tool discovery, has_tool/get_registered_names, MCP integration (session context injection; execution-context precedence), _convert_mcp_tool_to_framework_tool CONTEXT_PARAMS stripping, MCP config loading (list and dict formats; invalid JSON warning), and resync_mcp_servers_if_needed no-op cases.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I hopped through tests with eager paws,
Mapping hints to schemas without a pause,
Modules and MCPs now have a tune,
Contexts align beneath the moon,
Coverage blooms — a quiet cause.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding test coverage that increases tool_registry.py coverage from 47% to 69%.
Linked Issues check ✅ Passed The PR comprehensively addresses all coding requirements from issue #1972: tests cover register_function(), discover_from_module(), has_tool(), get_executor(), @tool decorator, and MCP integration.
Out of Scope Changes check ✅ Passed All changes are strictly within scope: only new test cases added to core/tests/test_tool_registry.py; no unrelated code modifications or runtime changes introduced.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
core/tests/test_tool_registry.py (2)

403-407: Please annotate the new test and fake-helper signatures.

The added tests/helpers still omit fixture and return annotations (tmp_path, monkeypatch, caplog, nested fake client/manager methods, etc.). Since this file is already expanding, please bring the new signatures in line with the repo standard; the same pattern repeats throughout the added block.

Representative cleanup
+from __future__ import annotations
+
 import logging
 import textwrap
 from pathlib import Path
 from types import SimpleNamespace
 
+import pytest
+
-def test_register_function_infers_type_hints():
+def test_register_function_infers_type_hints() -> None:
@@
-def test_discover_from_module_finds_tool_decorated_functions(tmp_path):
+def test_discover_from_module_finds_tool_decorated_functions(tmp_path: Path) -> None:
@@
-    class FakeClient:
-        def __init__(self, config):
+    class FakeClient:
+        def __init__(self, config: object) -> None:
             self.config = config
@@
-def test_load_mcp_config_handles_invalid_json(tmp_path, caplog):
+def test_load_mcp_config_handles_invalid_json(
+    tmp_path: Path, caplog: pytest.LogCaptureFixture
+) -> None:

As per coding guidelines, Use type hints on all function signatures and Use from __future__ import annotations for modern type syntax.

Also applies to: 488-490, 568-576, 626-633, 713-723, 776-785

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/tests/test_tool_registry.py` around lines 403 - 407, The new tests and
helper functions (e.g., test_register_function_infers_type_hints, any fake
client/manager methods, and helper fixtures that use tmp_path, monkeypatch,
caplog) are missing type annotations; add parameter and return type hints to
every function signature (e.g., tmp_path: Path, monkeypatch: pytest.MonkeyPatch,
caplog: pytest.LogCaptureFixture, and methods -> None or appropriate return
types) and ensure nested fake client/manager methods include their parameter and
return annotations; also add from __future__ import annotations at the top of
the file to match the repo standard.

717-717: Prefer double-quoted literals for these JSON fixtures.

These new payload strings are single-quoted. Switching them to double-quoted/triple-quoted strings—or generating them with json.dumps()—would keep the added test data aligned with the repo’s Python style.

As per coding guidelines, Use double quotes for strings.

Also applies to: 737-737, 779-779

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/tests/test_tool_registry.py` at line 717, Replace the single-quoted JSON
fixture string literals with proper double-quoted Python strings (or generate
them via json.dumps) so they follow the repo style; specifically update the
occurrences of the JSON payloads like '{"servers": [{"name": "s1", "transport":
"http", "url": "http://localhost:9000"}]}' (and the two other similar payload
strings noted in the comment) to use double-quoted/triple-quoted Python strings
or json.dumps(...) instead, keeping the internal JSON quoting intact and
ensuring tests still pass.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/tests/test_tool_registry.py`:
- Around line 403-419: Add a test that covers deferred (string) annotations:
create a temporary module (e.g., via types.ModuleType or importlib with source
that begins with "from __future__ import annotations") defining a function with
annotations like "int", "float", "bool", "dict", "list", "str", then call
ToolRegistry().register_function on that function and assert the resulting tool
(use registry.get_tools()["<name>"] and inspect tool.parameters["properties"])
maps to JSON types "integer","number","boolean","object","array","string" just
like test_register_function_infers_type_hints; this ensures
register_function/ToolRegistry handles forward/string annotations correctly.

---

Nitpick comments:
In `@core/tests/test_tool_registry.py`:
- Around line 403-407: The new tests and helper functions (e.g.,
test_register_function_infers_type_hints, any fake client/manager methods, and
helper fixtures that use tmp_path, monkeypatch, caplog) are missing type
annotations; add parameter and return type hints to every function signature
(e.g., tmp_path: Path, monkeypatch: pytest.MonkeyPatch, caplog:
pytest.LogCaptureFixture, and methods -> None or appropriate return types) and
ensure nested fake client/manager methods include their parameter and return
annotations; also add from __future__ import annotations at the top of the file
to match the repo standard.
- Line 717: Replace the single-quoted JSON fixture string literals with proper
double-quoted Python strings (or generate them via json.dumps) so they follow
the repo style; specifically update the occurrences of the JSON payloads like
'{"servers": [{"name": "s1", "transport": "http", "url":
"http://localhost:9000"}]}' (and the two other similar payload strings noted in
the comment) to use double-quoted/triple-quoted Python strings or
json.dumps(...) instead, keeping the internal JSON quoting intact and ensuring
tests still pass.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c72760d5-66fb-4360-b255-80cbf607c508

📥 Commits

Reviewing files that changed from the base of the PR and between c3c3075 and 4a01c7f.

📒 Files selected for processing (1)
  • core/tests/test_tool_registry.py

Comment on lines +403 to +419
def test_register_function_infers_type_hints():
"""register_function should map Python type annotations to JSON schema types."""
registry = ToolRegistry()

def my_func(a: int, b: float, c: bool, d: dict, e: list, f: str = "x") -> None:
pass

registry.register_function(my_func)

tool = registry.get_tools()["my_func"]
props = tool.parameters["properties"]
assert props["a"]["type"] == "integer"
assert props["b"]["type"] == "number"
assert props["c"]["type"] == "boolean"
assert props["d"]["type"] == "object"
assert props["e"]["type"] == "array"
assert props["f"]["type"] == "string"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine the production code's type annotation handling
fd -t f "tool_registry.py" | grep -v test | head -5

Repository: aden-hive/hive

Length of output: 96


🏁 Script executed:

# Check the relevant production code section
cat -n core/framework/runner/tool_registry.py | sed -n '100,140p'

Repository: aden-hive/hive

Length of output: 1732


🏁 Script executed:

# Examine the test file structure and imports
head -50 core/tests/test_tool_registry.py

Repository: aden-hive/hive

Length of output: 1736


🏁 Script executed:

# Check if there are any tests that specifically test with deferred annotations
rg "from __future__ import annotations" core/tests/test_tool_registry.py -A 5 -B 5

Repository: aden-hive/hive

Length of output: 40


🏁 Script executed:

# Look for any tests that import modules or use string annotations
rg "test.*annotation|test.*forward|test.*future" core/tests/test_tool_registry.py -i

Repository: aden-hive/hive

Length of output: 40


🏁 Script executed:

# Check if the test file has any imports of annotations utilities
rg "get_type_hints|typing.get_type_hints" core/tests/test_tool_registry.py

Repository: aden-hive/hive

Length of output: 40


🏁 Script executed:

# See how the production code file imports things at the top
head -30 core/framework/runner/tool_registry.py

Repository: aden-hive/hive

Length of output: 826


🏁 Script executed:

# Check if there's a pattern in the codebase for handling annotations properly
rg "get_type_hints|from __future__ import annotations" core/framework/ --type py | head -20

Repository: aden-hive/hive

Length of output: 1517


🏁 Script executed:

# Look at the full test around lines 403-419 to understand context
cat -n core/tests/test_tool_registry.py | sed -n '395,425p'

Repository: aden-hive/hive

Length of output: 1336


🏁 Script executed:

# Check if production tool files use deferred annotations (which would break the identity checks)
head -5 core/framework/tools/worker_monitoring_tools.py

Repository: aden-hive/hive

Length of output: 256


🏁 Script executed:

# Let's look at a real tool file to see how it's structured
cat -n core/framework/tools/worker_monitoring_tools.py | sed -n '1,80p'

Repository: aden-hive/hive

Length of output: 3745


🏁 Script executed:

# Check if typing.get_type_hints is used anywhere in the codebase for proper annotation handling
rg "get_type_hints" core/framework/

Repository: aden-hive/hive

Length of output: 40


🏁 Script executed:

# Verify the actual behavior: when deferred annotations are used, what does inspect.signature return?
python3 << 'EOF'
import inspect

# Case 1: eager annotations (no from __future__)
def eager_func(a: int) -> None:
    pass

# Case 2: deferred annotations (simulating what happens with from __future__)
# We need to manually set __annotations__ as strings to simulate deferred behavior
def deferred_func(a: int) -> None:
    pass
deferred_func.__annotations__ = {'a': 'int', 'return': 'None'}

print("Eager annotation identity check:")
sig_eager = inspect.signature(eager_func)
param_eager = sig_eager.parameters['a']
print(f"  param.annotation: {param_eager.annotation}")
print(f"  param.annotation is int: {param_eager.annotation is int}")
print(f"  param.annotation == int: {param_eager.annotation == int}")

print("\nDeferred annotation identity check:")
sig_deferred = inspect.signature(deferred_func)
param_deferred = sig_deferred.parameters['a']
print(f"  param.annotation: {param_deferred.annotation}")
print(f"  param.annotation is int: {param_deferred.annotation is int}")
print(f"  param.annotation == int: {param_deferred.annotation == int}")
EOF

Repository: aden-hive/hive

Length of output: 315


🏁 Script executed:

# Check if tool_registry.py has any handling for string annotations
rg "typing.get_type_hints|str.*annotation|forward ref" core/framework/runner/tool_registry.py

Repository: aden-hive/hive

Length of output: 40


🏁 Script executed:

# Look at the actual annotations in inspect.signature when deferred
python3 << 'EOF'
import inspect

# Simulate what happens when a tool module with from __future__ import annotations
# registers a function
def tool_func(x: int, y: str) -> None:
    pass

# Override __annotations__ to simulate deferred behavior
tool_func.__annotations__ = {'x': 'int', 'y': 'str', 'return': 'None'}

sig = inspect.signature(tool_func)
for param_name, param in sig.parameters.items():
    print(f"{param_name}: annotation={param.annotation!r}, type={type(param.annotation)}, is int: {param.annotation is int}")
EOF

Repository: aden-hive/hive

Length of output: 167


🏁 Script executed:

# Check if there are any test modules that actually use from __future__ import annotations
rg "from __future__ import annotations" core/tests/ --type py

Repository: aden-hive/hive

Length of output: 2034


🏁 Script executed:

# See if there's any existing test of type inference with string annotations
rg "def test.*type" core/tests/test_tool_registry.py -A 3

Repository: aden-hive/hive

Length of output: 221


🏁 Script executed:

# Check if tool_registry.py or any other code handles string annotations via get_type_hints
rg "get_type_hints" core/framework/ --type py -B 2 -A 5

Repository: aden-hive/hive

Length of output: 40


🏁 Script executed:

# Verify that tool_registry.py does NOT have from __future__ import annotations
head -20 core/framework/runner/tool_registry.py | grep -E "from __future__|^import"

Repository: aden-hive/hive

Length of output: 165


🏁 Script executed:

# Check what the test file imports at the top
head -30 core/tests/test_tool_registry.py

Repository: aden-hive/hive

Length of output: 1089


Test only validates eager-annotation path; will miss schema inference failures with deferred annotations.

test_register_function_infers_type_hints() uses bare runtime annotations, but core/framework/runner/tool_registry.py:108-128 infers schema types via identity checks (param.annotation is int). When a tool module uses from __future__ import annotations (as many production tools do—e.g., worker_monitoring_tools.py), those annotations are strings at runtime. The identity checks fail and silently default to "string" for all parameters.

Add a test case with deferred annotations (e.g., by creating a temporary module with from __future__ import annotations and registering functions from it) to verify the schema mapping works correctly in that scenario.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/tests/test_tool_registry.py` around lines 403 - 419, Add a test that
covers deferred (string) annotations: create a temporary module (e.g., via
types.ModuleType or importlib with source that begins with "from __future__
import annotations") defining a function with annotations like "int", "float",
"bool", "dict", "list", "str", then call ToolRegistry().register_function on
that function and assert the resulting tool (use registry.get_tools()["<name>"]
and inspect tool.parameters["properties"]) maps to JSON types
"integer","number","boolean","object","array","string" just like
test_register_function_infers_type_hints; this ensures
register_function/ToolRegistry handles forward/string annotations correctly.

@Hundao
Hundao merged commit 5e628c7 into aden-hive:main Apr 1, 2026
8 of 9 checks passed
RodrigoMvs123 pushed a commit to RodrigoMvs123/Aden-Hive that referenced this pull request Apr 6, 2026
…e#6818)

* test(core): increase tool_registry coverage from 47% to 69%

Add 19 new tests covering previously untested paths in ToolRegistry:

- register_function: type hint inference (int/float/bool/dict/list),
  required vs optional params, custom name/description, docstring fallback,
  executor delegation
- discover_from_module: @tool decorator pickup, missing-file zero-count,
  TOOLS dict without tool_executor uses mock executor
- has_tool / get_registered_names basic assertions
- Session context injection into MCP tool calls via set_session_context()
- Execution context override (contextvars) wins over session context
- _convert_mcp_tool_to_framework_tool: strips CONTEXT_PARAMS from both
  properties and required lists
- load_mcp_config: list format, dict format, graceful invalid-JSON warning
- resync_mcp_servers_if_needed: returns False with no clients; returns
  False when credentials and ADEN_API_KEY are unchanged

Coverage: 47 % → 69 % (+22 pp), all 31 tests pass, ruff clean.

Relates to aden-hive#1972

* style: fix formatting in test_tool_registry.py

* fix: accept **kwargs in fake_load_registry to match updated signature

---------

Co-authored-by: hundao <alchemy_wimp@hotmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test(core): Add test coverage for tool_registry.py

2 participants