We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/hqtrung/finizi-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""Comprehensive tests for product management functionality."""
import json
import pytest
from unittest.mock import Mock, AsyncMock, patch
import httpx
from src.finizi_b4b_mcp.tools.products import list_products, search_similar_products
# Load mock responses
with open("tests/fixtures/mock_responses.json") as f:
MOCK_RESPONSES = json.load(f)
# Tests for list_products function
@pytest.mark.asyncio
async def test_list_products_success():
"""Test listing products with pagination."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {"user_token": "fake_token"}
mock_response = MOCK_RESPONSES["products"]["list_success"]
with patch('src.finizi_b4b_mcp.tools.products.get_api_client') as mock_client:
mock_api = Mock()
mock_api.get = AsyncMock(return_value=mock_response)
mock_client.return_value = mock_api
result = await list_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
page=1,
per_page=20,
ctx=ctx
)
assert result["success"] is True
assert "products" in result
assert len(result["products"]["data"]) == 2
assert result["products"]["total"] == 2
assert result["products"]["data"][0]["name"] == "Product A"
assert result["products"]["data"][0]["sku"] == "SKU-001"
@pytest.mark.asyncio
async def test_list_products_with_filters():
"""Test listing products with category and search filters."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {"user_token": "fake_token"}
mock_response = {
"data": [MOCK_RESPONSES["products"]["list_success"]["data"][0]],
"total": 1,
"page": 1,
"per_page": 20
}
with patch('src.finizi_b4b_mcp.tools.products.get_api_client') as mock_client:
mock_api = Mock()
mock_api.get = AsyncMock(return_value=mock_response)
mock_client.return_value = mock_api
result = await list_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
page=1,
per_page=20,
category="electronics",
search="Product A",
ctx=ctx
)
assert result["success"] is True
assert len(result["products"]["data"]) == 1
assert result["products"]["data"][0]["category"] == "electronics"
@pytest.mark.asyncio
async def test_list_products_not_authenticated():
"""Test listing products without authentication."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {}
result = await list_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
page=1,
per_page=20,
ctx=ctx
)
# Updated to match actual error format from products.py
assert result["success"] is False
assert ("authentication" in result["error"].lower() or "validation error" in result["error"].lower())
@pytest.mark.asyncio
async def test_list_products_forbidden():
"""Test 403 error when access is denied to entity products."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {"user_token": "fake_token"}
mock_response = Mock()
mock_response.status_code = 403
mock_response.json.return_value = MOCK_RESPONSES["errors"]["forbidden_403"]
mock_response.text = "Forbidden"
with patch('src.finizi_b4b_mcp.tools.products.get_api_client') as mock_client:
mock_api = Mock()
mock_api.get = AsyncMock(side_effect=httpx.HTTPStatusError(
"Forbidden",
request=Mock(),
response=mock_response
))
mock_client.return_value = mock_api
result = await list_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
page=1,
per_page=20,
ctx=ctx
)
# Updated to match actual error format from products.py
assert result["success"] is False
assert ("access" in result["error"].lower() or "forbidden" in result["error"].lower())
@pytest.mark.asyncio
async def test_list_products_entity_not_found():
"""Test 404 error when entity doesn't exist."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {"user_token": "fake_token"}
mock_response = Mock()
mock_response.status_code = 404
mock_response.json.return_value = MOCK_RESPONSES["errors"]["not_found_404"]
mock_response.text = "Not Found"
with patch('src.finizi_b4b_mcp.tools.products.get_api_client') as mock_client:
mock_api = Mock()
mock_api.get = AsyncMock(side_effect=httpx.HTTPStatusError(
"Not Found",
request=Mock(),
response=mock_response
))
mock_client.return_value = mock_api
result = await list_products(
entity_id="nonexistent-entity-id",
page=1,
per_page=20,
ctx=ctx
)
# Updated to match actual error format from products.py
assert result["success"] is False
assert "not found" in result["error"].lower()
@pytest.mark.asyncio
async def test_list_products_invalid_pagination():
"""Test validation error with invalid pagination parameters."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {"user_token": "fake_token"}
result = await list_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
page=0,
per_page=20,
ctx=ctx
)
assert result["success"] is False
assert "Validation error" in result["error"]
# Tests for search_similar_products function
@pytest.mark.asyncio
async def test_search_similar_products_success():
"""Test semantic search for similar products."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {"user_token": "fake_token"}
mock_response = MOCK_RESPONSES["products"]["search_similar_success"]
with patch('src.finizi_b4b_mcp.tools.products.get_api_client') as mock_client:
mock_api = Mock()
mock_api.post = AsyncMock(return_value=mock_response)
mock_client.return_value = mock_api
result = await search_similar_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
product_name="Product A",
top_k=5,
ctx=ctx
)
assert result["success"] is True
assert "similar_products" in result
assert len(result["similar_products"]["results"]) == 2
assert result["similar_products"]["results"][0]["name"] == "Product A"
assert result["similar_products"]["results"][0]["similarity_score"] == 0.95
assert result["similar_products"]["query"] == "Product A"
@pytest.mark.asyncio
async def test_search_similar_products_custom_top_k():
"""Test similar products search with custom top_k value."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {"user_token": "fake_token"}
mock_response = {
"results": [MOCK_RESPONSES["products"]["search_similar_success"]["results"][0]],
"query": "Product A",
"total_results": 1
}
with patch('src.finizi_b4b_mcp.tools.products.get_api_client') as mock_client:
mock_api = Mock()
mock_api.post = AsyncMock(return_value=mock_response)
mock_client.return_value = mock_api
result = await search_similar_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
product_name="Product A",
top_k=1,
ctx=ctx
)
assert result["success"] is True
assert len(result["similar_products"]["results"]) == 1
@pytest.mark.asyncio
async def test_search_similar_products_invalid_top_k():
"""Test validation error with invalid top_k value."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {"user_token": "fake_token"}
# Test top_k = 0
result = await search_similar_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
product_name="Product A",
top_k=0,
ctx=ctx
)
assert result["success"] is False
assert "top_k must be greater than 0" in result["error"]
# Test top_k > 100
result = await search_similar_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
product_name="Product A",
top_k=101,
ctx=ctx
)
assert result["success"] is False
assert "top_k cannot exceed 100" in result["error"]
@pytest.mark.asyncio
async def test_search_similar_products_empty_product_name():
"""Test validation error with empty product name."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {"user_token": "fake_token"}
result = await search_similar_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
product_name="",
top_k=5,
ctx=ctx
)
assert result["success"] is False
assert "product_name cannot be empty" in result["error"]
@pytest.mark.asyncio
async def test_search_similar_products_not_authenticated():
"""Test searching similar products without authentication."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {}
result = await search_similar_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
product_name="Product A",
top_k=5,
ctx=ctx
)
# Updated to match actual error format from products.py
assert result["success"] is False
assert ("authentication" in result["error"].lower() or "validation error" in result["error"].lower())
@pytest.mark.asyncio
async def test_search_similar_products_forbidden():
"""Test 403 error when access is denied."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {"user_token": "fake_token"}
mock_response = Mock()
mock_response.status_code = 403
mock_response.json.return_value = MOCK_RESPONSES["errors"]["forbidden_403"]
mock_response.text = "Forbidden"
with patch('src.finizi_b4b_mcp.tools.products.get_api_client') as mock_client:
mock_api = Mock()
mock_api.post = AsyncMock(side_effect=httpx.HTTPStatusError(
"Forbidden",
request=Mock(),
response=mock_response
))
mock_client.return_value = mock_api
result = await search_similar_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
product_name="Product A",
top_k=5,
ctx=ctx
)
# Updated to match actual error format from products.py
assert result["success"] is False
assert ("access" in result["error"].lower() or "forbidden" in result["error"].lower())
@pytest.mark.asyncio
async def test_search_similar_products_entity_not_found():
"""Test 404 error when entity doesn't exist."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {"user_token": "fake_token"}
mock_response = Mock()
mock_response.status_code = 404
mock_response.json.return_value = MOCK_RESPONSES["errors"]["not_found_404"]
mock_response.text = "Not Found"
with patch('src.finizi_b4b_mcp.tools.products.get_api_client') as mock_client:
mock_api = Mock()
mock_api.post = AsyncMock(side_effect=httpx.HTTPStatusError(
"Not Found",
request=Mock(),
response=mock_response
))
mock_client.return_value = mock_api
result = await search_similar_products(
entity_id="nonexistent-entity-id",
product_name="Product A",
top_k=5,
ctx=ctx
)
# Updated to match actual error format from products.py
assert result["success"] is False
assert "not found" in result["error"].lower()
@pytest.mark.asyncio
async def test_search_similar_products_unexpected_error():
"""Test handling of unexpected errors."""
ctx = Mock()
ctx.session = Mock()
ctx.session.metadata = {"user_token": "fake_token"}
with patch('src.finizi_b4b_mcp.tools.products.get_api_client') as mock_client:
mock_api = Mock()
mock_api.post = AsyncMock(side_effect=Exception("Unexpected error"))
mock_client.return_value = mock_api
result = await search_similar_products(
entity_id="123e4567-e89b-12d3-a456-426614174000",
product_name="Product A",
top_k=5,
ctx=ctx
)
# Updated to match actual error format from products.py
assert result["success"] is False
assert ("unexpected error" in result["error"].lower() or "error" in result["error"].lower())