Skip to content

Commit 72fdee3

Browse files
committed
add more test cases
1 parent 4b6ca80 commit 72fdee3

File tree

1 file changed

+178
-0
lines changed

1 file changed

+178
-0
lines changed

tests/test_configuration.py

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,3 +437,181 @@ async def search_items():
437437

438438
with pytest.raises(ValueError):
439439
FastApiMCP(app, include_tags=["items"], exclude_tags=["write"])
440+
441+
442+
def test_filtering_edge_cases():
443+
"""Test edge cases for the filtering functionality."""
444+
app = FastAPI()
445+
446+
# Define endpoints with different operation IDs and tags
447+
@app.get("/items/", operation_id="list_items", tags=["items"])
448+
async def list_items():
449+
return [{"id": 1}]
450+
451+
@app.get("/items/{item_id}", operation_id="get_item", tags=["items", "read"])
452+
async def get_item(item_id: int):
453+
return {"id": item_id}
454+
455+
# Test with no filtering (default behavior)
456+
default_mcp = FastApiMCP(app)
457+
assert len(default_mcp.tools) == 2
458+
assert {tool.name for tool in default_mcp.tools} == {"get_item", "list_items"}
459+
460+
# Test with empty include_operations
461+
empty_include_ops_mcp = FastApiMCP(app, include_operations=[])
462+
assert len(empty_include_ops_mcp.tools) == 0
463+
assert empty_include_ops_mcp.tools == []
464+
465+
# Test with empty exclude_operations (should include all)
466+
empty_exclude_ops_mcp = FastApiMCP(app, exclude_operations=[])
467+
assert len(empty_exclude_ops_mcp.tools) == 2
468+
assert {tool.name for tool in empty_exclude_ops_mcp.tools} == {"get_item", "list_items"}
469+
470+
# Test with empty include_tags
471+
empty_include_tags_mcp = FastApiMCP(app, include_tags=[])
472+
assert len(empty_include_tags_mcp.tools) == 0
473+
assert empty_include_tags_mcp.tools == []
474+
475+
# Test with empty exclude_tags (should include all)
476+
empty_exclude_tags_mcp = FastApiMCP(app, exclude_tags=[])
477+
assert len(empty_exclude_tags_mcp.tools) == 2
478+
assert {tool.name for tool in empty_exclude_tags_mcp.tools} == {"get_item", "list_items"}
479+
480+
# Test with non-existent operation IDs
481+
nonexistent_ops_mcp = FastApiMCP(app, include_operations=["non_existent_op"])
482+
assert len(nonexistent_ops_mcp.tools) == 0
483+
assert nonexistent_ops_mcp.tools == []
484+
485+
# Test with non-existent tags
486+
nonexistent_tags_mcp = FastApiMCP(app, include_tags=["non_existent_tag"])
487+
assert len(nonexistent_tags_mcp.tools) == 0
488+
assert nonexistent_tags_mcp.tools == []
489+
490+
# Test excluding non-existent operation IDs
491+
exclude_nonexistent_ops_mcp = FastApiMCP(app, exclude_operations=["non_existent_op"])
492+
assert len(exclude_nonexistent_ops_mcp.tools) == 2
493+
assert {tool.name for tool in exclude_nonexistent_ops_mcp.tools} == {"get_item", "list_items"}
494+
495+
# Test excluding non-existent tags
496+
exclude_nonexistent_tags_mcp = FastApiMCP(app, exclude_tags=["non_existent_tag"])
497+
assert len(exclude_nonexistent_tags_mcp.tools) == 2
498+
assert {tool.name for tool in exclude_nonexistent_tags_mcp.tools} == {"get_item", "list_items"}
499+
500+
# Test with an endpoint that has no tags
501+
@app.get("/no-tags", operation_id="no_tags")
502+
async def no_tags():
503+
return {"result": "no tags"}
504+
505+
# Test include_tags with an endpoint that has no tags
506+
no_tags_app_mcp = FastApiMCP(app, include_tags=["items"])
507+
assert len(no_tags_app_mcp.tools) == 2
508+
assert "no_tags" not in {tool.name for tool in no_tags_app_mcp.tools}
509+
510+
# Test exclude_tags with an endpoint that has no tags
511+
no_tags_exclude_mcp = FastApiMCP(app, exclude_tags=["items"])
512+
assert len(no_tags_exclude_mcp.tools) == 1
513+
assert {tool.name for tool in no_tags_exclude_mcp.tools} == {"no_tags"}
514+
515+
516+
def test_filtering_with_missing_operation_ids():
517+
"""Test filtering behavior with endpoints that don't have operation IDs."""
518+
app = FastAPI()
519+
520+
# Define an endpoint with an operation ID
521+
@app.get("/items/", operation_id="list_items", tags=["items"])
522+
async def list_items():
523+
return [{"id": 1}]
524+
525+
# Define an endpoint without an operation ID
526+
@app.get("/no-op-id/")
527+
async def no_op_id():
528+
return {"result": "no operation ID"}
529+
530+
# Test that both endpoints are discovered
531+
default_mcp = FastApiMCP(app)
532+
533+
# FastAPI-MCP will generate an operation ID for endpoints without one
534+
# The auto-generated ID will typically be 'no_op_id_no_op_id__get'
535+
assert len(default_mcp.tools) == 2
536+
537+
# Get the auto-generated operation ID
538+
auto_generated_op_id = None
539+
for tool in default_mcp.tools:
540+
if tool.name != "list_items":
541+
auto_generated_op_id = tool.name
542+
break
543+
544+
assert auto_generated_op_id is not None
545+
assert "list_items" in {tool.name for tool in default_mcp.tools}
546+
547+
# Test include_operations with the known operation ID
548+
include_ops_mcp = FastApiMCP(app, include_operations=["list_items"])
549+
assert len(include_ops_mcp.tools) == 1
550+
assert {tool.name for tool in include_ops_mcp.tools} == {"list_items"}
551+
552+
# Test include_operations with the auto-generated operation ID
553+
include_auto_ops_mcp = FastApiMCP(app, include_operations=[auto_generated_op_id])
554+
assert len(include_auto_ops_mcp.tools) == 1
555+
assert {tool.name for tool in include_auto_ops_mcp.tools} == {auto_generated_op_id}
556+
557+
# Test include_tags with a tag that matches the endpoint
558+
include_tags_mcp = FastApiMCP(app, include_tags=["items"])
559+
assert len(include_tags_mcp.tools) == 1
560+
assert {tool.name for tool in include_tags_mcp.tools} == {"list_items"}
561+
562+
563+
def test_filter_with_empty_tools():
564+
"""Test filtering with an empty tools list to ensure it handles this edge case correctly."""
565+
# Create a FastAPI app without any routes
566+
app = FastAPI()
567+
568+
# Create MCP server (should have no tools)
569+
empty_mcp = FastApiMCP(app)
570+
assert len(empty_mcp.tools) == 0
571+
572+
# Test filtering with various options on an empty app
573+
include_ops_mcp = FastApiMCP(app, include_operations=["some_op"])
574+
assert len(include_ops_mcp.tools) == 0
575+
576+
exclude_ops_mcp = FastApiMCP(app, exclude_operations=["some_op"])
577+
assert len(exclude_ops_mcp.tools) == 0
578+
579+
include_tags_mcp = FastApiMCP(app, include_tags=["some_tag"])
580+
assert len(include_tags_mcp.tools) == 0
581+
582+
exclude_tags_mcp = FastApiMCP(app, exclude_tags=["some_tag"])
583+
assert len(exclude_tags_mcp.tools) == 0
584+
585+
# Test combined filtering
586+
combined_mcp = FastApiMCP(app, include_operations=["op"], include_tags=["tag"])
587+
assert len(combined_mcp.tools) == 0
588+
589+
590+
def test_filtering_with_empty_tags_array():
591+
"""Test filtering behavior with endpoints that have empty tags array."""
592+
app = FastAPI()
593+
594+
# Define an endpoint with tags
595+
@app.get("/items/", operation_id="list_items", tags=["items"])
596+
async def list_items():
597+
return [{"id": 1}]
598+
599+
# Define an endpoint with an empty tags array
600+
@app.get("/empty-tags/", operation_id="empty_tags", tags=[])
601+
async def empty_tags():
602+
return {"result": "empty tags"}
603+
604+
# Test default behavior
605+
default_mcp = FastApiMCP(app)
606+
assert len(default_mcp.tools) == 2
607+
assert {tool.name for tool in default_mcp.tools} == {"list_items", "empty_tags"}
608+
609+
# Test include_tags
610+
include_tags_mcp = FastApiMCP(app, include_tags=["items"])
611+
assert len(include_tags_mcp.tools) == 1
612+
assert {tool.name for tool in include_tags_mcp.tools} == {"list_items"}
613+
614+
# Test exclude_tags
615+
exclude_tags_mcp = FastApiMCP(app, exclude_tags=["items"])
616+
assert len(exclude_tags_mcp.tools) == 1
617+
assert {tool.name for tool in exclude_tags_mcp.tools} == {"empty_tags"}

0 commit comments

Comments
 (0)