Skip to content

Commit 3bb4df7

Browse files
committed
chore: Add unit test coverage
1 parent 5ff4b7b commit 3bb4df7

File tree

1 file changed

+148
-18
lines changed

1 file changed

+148
-18
lines changed

packages/toolbox-core/tests/test_tool.py

Lines changed: 148 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
from aiohttp import ClientSession
2323
from aioresponses import aioresponses
2424
from pydantic import ValidationError
25+
from warnings import catch_warnings, simplefilter
2526

2627
from toolbox_core.protocol import ParameterSchema
2728
from toolbox_core.tool import ToolboxTool, create_func_docstring, resolve_value
2829

2930
TEST_BASE_URL = "http://toolbox.example.com"
31+
HTTPS_BASE_URL = "https://toolbox.example.com"
3032
TEST_TOOL_NAME = "sample_tool"
3133

3234

@@ -195,7 +197,7 @@ async def test_tool_creation_callable_and_run(
195197
Tests creating a ToolboxTool, checks callability, and simulates a run.
196198
"""
197199
tool_name = TEST_TOOL_NAME
198-
base_url = TEST_BASE_URL
200+
base_url = HTTPS_BASE_URL
199201
invoke_url = f"{base_url}/api/tool/{tool_name}/invoke"
200202

201203
input_args = {"message": "hello world", "count": 5}
@@ -246,7 +248,7 @@ async def test_tool_run_with_pydantic_validation_error(
246248
due to Pydantic validation *before* making an HTTP request.
247249
"""
248250
tool_name = TEST_TOOL_NAME
249-
base_url = TEST_BASE_URL
251+
base_url = HTTPS_BASE_URL
250252
invoke_url = f"{base_url}/api/tool/{tool_name}/invoke"
251253

252254
with aioresponses() as m:
@@ -340,18 +342,23 @@ async def test_resolve_value_async_callable():
340342

341343
def test_tool_init_basic(http_session, sample_tool_params, sample_tool_description):
342344
"""Tests basic tool initialization without headers or auth."""
343-
tool_instance = ToolboxTool(
344-
session=http_session,
345-
base_url=TEST_BASE_URL,
346-
name=TEST_TOOL_NAME,
347-
description=sample_tool_description,
348-
params=sample_tool_params,
349-
required_authn_params={},
350-
required_authz_tokens=[],
351-
auth_service_token_getters={},
352-
bound_params={},
353-
client_headers={},
354-
)
345+
with catch_warnings(record=True) as record:
346+
simplefilter("always")
347+
348+
tool_instance = ToolboxTool(
349+
session=http_session,
350+
base_url=HTTPS_BASE_URL,
351+
name=TEST_TOOL_NAME,
352+
description=sample_tool_description,
353+
params=sample_tool_params,
354+
required_authn_params={},
355+
required_authz_tokens=[],
356+
auth_service_token_getters={},
357+
bound_params={},
358+
client_headers={},
359+
)
360+
assert len(record) == 0, f"ToolboxTool instantiation unexpectedly warned: {[f'{w.category.__name__}: {w.message}' for w in record]}"
361+
355362
assert tool_instance.__name__ == TEST_TOOL_NAME
356363
assert inspect.iscoroutinefunction(tool_instance.__call__)
357364
assert "message" in tool_instance.__signature__.parameters
@@ -367,7 +374,7 @@ def test_tool_init_with_client_headers(
367374
"""Tests tool initialization *with* client headers."""
368375
tool_instance = ToolboxTool(
369376
session=http_session,
370-
base_url=TEST_BASE_URL,
377+
base_url=HTTPS_BASE_URL,
371378
name=TEST_TOOL_NAME,
372379
description=sample_tool_description,
373380
params=sample_tool_params,
@@ -395,7 +402,7 @@ def test_tool_init_header_auth_conflict(
395402
):
396403
ToolboxTool(
397404
session=http_session,
398-
base_url=TEST_BASE_URL,
405+
base_url=HTTPS_BASE_URL,
399406
name="auth_conflict_tool",
400407
description=sample_tool_description,
401408
params=sample_tool_auth_params,
@@ -418,7 +425,7 @@ def test_tool_add_auth_token_getters_conflict_with_existing_client_header(
418425
"""
419426
tool_instance = ToolboxTool(
420427
session=http_session,
421-
base_url=TEST_BASE_URL,
428+
base_url=HTTPS_BASE_URL,
422429
name="tool_with_client_header",
423430
description=sample_tool_description,
424431
params=sample_tool_params,
@@ -454,7 +461,7 @@ def test_add_auth_token_getters_unused_token(
454461
"""
455462
tool_instance = ToolboxTool(
456463
session=http_session,
457-
base_url=TEST_BASE_URL,
464+
base_url=HTTPS_BASE_URL,
458465
name=TEST_TOOL_NAME,
459466
description=sample_tool_description,
460467
params=sample_tool_params,
@@ -469,3 +476,126 @@ def test_add_auth_token_getters_unused_token(
469476

470477
with pytest.raises(ValueError, match=expected_error_message):
471478
tool_instance.add_auth_token_getters(unused_auth_getters)
479+
480+
481+
# --- Test for the HTTP Warning ---
482+
@pytest.mark.parametrize(
483+
"trigger_condition_params",
484+
[
485+
{"client_headers": {"X-Some-Header": "value"}},
486+
{"required_authn_params": {"param1": ["auth-service1"]}},
487+
{"required_authz_tokens": ["auth-service2"]},
488+
{
489+
"client_headers": {"X-Some-Header": "value"},
490+
"required_authn_params": {"param1": ["auth-service1"]},
491+
},
492+
{
493+
"client_headers": {"X-Some-Header": "value"},
494+
"required_authz_tokens": ["auth-service2"],
495+
},
496+
{
497+
"required_authn_params": {"param1": ["auth-service1"]},
498+
"required_authz_tokens": ["auth-service2"],
499+
},
500+
{
501+
"client_headers": {"X-Some-Header": "value"},
502+
"required_authn_params": {"param1": ["auth-service1"]},
503+
"required_authz_tokens": ["auth-service2"],
504+
},
505+
],
506+
ids=[
507+
"client_headers_only",
508+
"authn_params_only",
509+
"authz_tokens_only",
510+
"headers_and_authn",
511+
"headers_and_authz",
512+
"authn_and_authz",
513+
"all_three_conditions",
514+
],
515+
)
516+
def test_tool_init_http_warning_when_sensitive_info_over_http(
517+
http_session: ClientSession,
518+
sample_tool_params: list[ParameterSchema],
519+
sample_tool_description: str,
520+
trigger_condition_params: dict,
521+
):
522+
"""
523+
Tests that a UserWarning is issued if client headers, auth params, or
524+
auth tokens are present and the base_url is HTTP.
525+
"""
526+
expected_warning_message = (
527+
"Sending ID token over HTTP. User data may be exposed. "
528+
"Use HTTPS for secure communication."
529+
)
530+
531+
init_kwargs = {
532+
"session": http_session,
533+
"base_url": TEST_BASE_URL,
534+
"name": "http_warning_tool",
535+
"description": sample_tool_description,
536+
"params": sample_tool_params,
537+
"required_authn_params": {},
538+
"required_authz_tokens": [],
539+
"auth_service_token_getters": {},
540+
"bound_params": {},
541+
"client_headers": {},
542+
}
543+
# Apply the specific conditions for this parametrized test
544+
init_kwargs.update(trigger_condition_params)
545+
546+
with pytest.warns(UserWarning, match=expected_warning_message):
547+
ToolboxTool(**init_kwargs)
548+
549+
550+
def test_tool_init_no_http_warning_if_https(
551+
http_session: ClientSession,
552+
sample_tool_params: list[ParameterSchema],
553+
sample_tool_description: str,
554+
static_client_header: dict,
555+
):
556+
"""
557+
Tests that NO UserWarning is issued if client headers are present but
558+
the base_url is HTTPS.
559+
"""
560+
with catch_warnings(record=True) as record:
561+
simplefilter("always")
562+
563+
ToolboxTool(
564+
session=http_session,
565+
base_url=HTTPS_BASE_URL,
566+
name="https_tool",
567+
description=sample_tool_description,
568+
params=sample_tool_params,
569+
required_authn_params={},
570+
required_authz_tokens=[],
571+
auth_service_token_getters={},
572+
bound_params={},
573+
client_headers=static_client_header,
574+
)
575+
assert len(record) == 0, f"Expected no warnings, but got: {[f'{w.category.__name__}: {w.message}' for w in record]}"
576+
577+
def test_tool_init_no_http_warning_if_no_sensitive_info_on_http(
578+
http_session: ClientSession,
579+
sample_tool_params: list[ParameterSchema],
580+
sample_tool_description: str,
581+
):
582+
"""
583+
Tests that NO UserWarning is issued if the URL is HTTP but there are
584+
no client headers, auth params, or auth tokens.
585+
"""
586+
with catch_warnings(record=True) as record:
587+
simplefilter("always")
588+
589+
ToolboxTool(
590+
session=http_session,
591+
base_url=TEST_BASE_URL,
592+
name="http_tool_no_sensitive",
593+
description=sample_tool_description,
594+
params=sample_tool_params,
595+
required_authn_params={},
596+
required_authz_tokens=[],
597+
auth_service_token_getters={},
598+
bound_params={},
599+
client_headers={},
600+
)
601+
assert len(record) == 0, f"Expected no warnings, but got: {[f'{w.category.__name__}: {w.message}' for w in record]}"

0 commit comments

Comments
 (0)