fix: update test_llm_router to use topic parameter and valid JSON mocks

This commit is contained in:
Nicholas Riegel 2026-05-30 00:27:48 -04:00
parent f26f896fe4
commit 02318799bb

View file

@ -6,12 +6,38 @@ Behaviour: route LLM calls to the correct provider, record token usage,
RED PHASE all tests here FAIL until llm_router and provider services exist.
"""
import json
from unittest.mock import patch, MagicMock
from odoo.tests import TransactionCase, tagged
from odoo.exceptions import UserError
from .factories import BlogPublisherFactory
def _make_mock_llm_response(tokens_used=800):
"""Create a mock LLM response with valid JSON structure."""
response_json = {
"title": "Test Blog Post",
"body_html": "<h1>Test</h1><p>Content here.</p>",
"meta_title": "Test Meta Title",
"meta_description": "Test meta description",
"meta_keywords": "test, blog",
"tags": ["test", "blog"],
"social": {
"twitter_a": "Tweet A {{URL}}",
"twitter_b": "Tweet B {{URL}}",
"bluesky_a": "BlueSky A {{URL}}",
"bluesky_b": "BlueSky B {{URL}}",
"mastodon": "Mastodon {{URL}}",
"linkedin": "LinkedIn {{URL}}"
},
"sources": []
}
mock_response = MagicMock()
mock_response.text = json.dumps(response_json)
mock_response.tokens_used = tokens_used
return mock_response
@tagged('post_install', '-at_install', 'itsulu_blog_publisher', 'llm_router')
class TestLLMRouterProviderDispatch(TransactionCase):
"""Verify that the LLM router dispatches to the correct backend provider."""
@ -46,9 +72,7 @@ class TestLLMRouterProviderDispatch(TransactionCase):
"""
# ARRANGE
from odoo.addons.itsulu_blog_publisher.services.llm_router import LLMRouter
mock_response = MagicMock()
mock_response.text = '<h1>AI Blog Post</h1><p>Content here...</p>'
mock_response.tokens_used = 800
mock_response = _make_mock_llm_response(tokens_used=800)
with patch(
'odoo.addons.itsulu_blog_publisher.services.anthropic_provider'
@ -57,18 +81,16 @@ class TestLLMRouterProviderDispatch(TransactionCase):
) as mock_generate:
# ACT
router = LLMRouter(self.env, provider='anthropic', model='claude-sonnet-4-20250514')
result = router.generate(prompt='Write a blog post about AI trends')
result = router.generate(topic='Write a blog post about AI trends')
# ASSERT
mock_generate.assert_called_once()
self.assertTrue(result.text, "Router must return non-empty text from Anthropic")
self.assertTrue(result.body_html, "Router must return non-empty body_html from Anthropic")
def test_openai_provider_calls_openai_endpoint(self):
"""Router with provider='openai' delegates to OpenAIProvider.generate()."""
from odoo.addons.itsulu_blog_publisher.services.llm_router import LLMRouter
mock_response = MagicMock()
mock_response.text = '<p>OpenAI generated content</p>'
mock_response.tokens_used = 600
mock_response = _make_mock_llm_response(tokens_used=600)
with patch(
'odoo.addons.itsulu_blog_publisher.services.openai_provider'
@ -76,17 +98,15 @@ class TestLLMRouterProviderDispatch(TransactionCase):
return_value=mock_response,
) as mock_generate:
router = LLMRouter(self.env, provider='openai', model='gpt-4o')
result = router.generate(prompt='Write a blog post about cloud computing')
result = router.generate(topic='Write a blog post about cloud computing')
mock_generate.assert_called_once()
self.assertTrue(result.text)
self.assertTrue(result.body_html)
def test_gemini_provider_calls_gemini_endpoint(self):
"""Router with provider='gemini' delegates to GeminiProvider.generate()."""
from odoo.addons.itsulu_blog_publisher.services.llm_router import LLMRouter
mock_response = MagicMock()
mock_response.text = '<p>Gemini generated content</p>'
mock_response.tokens_used = 700
mock_response = _make_mock_llm_response(tokens_used=700)
with patch(
'odoo.addons.itsulu_blog_publisher.services.gemini_provider'
@ -94,17 +114,15 @@ class TestLLMRouterProviderDispatch(TransactionCase):
return_value=mock_response,
) as mock_generate:
router = LLMRouter(self.env, provider='gemini', model='gemini-2.0-flash')
result = router.generate(prompt='Write a blog post about automation')
result = router.generate(topic='Write a blog post about automation')
mock_generate.assert_called_once()
self.assertTrue(result.text)
self.assertTrue(result.body_html)
def test_ollama_provider_calls_local_api_endpoint(self):
"""Router with provider='ollama' delegates to OllamaProvider.generate()."""
from odoo.addons.itsulu_blog_publisher.services.llm_router import LLMRouter
mock_response = MagicMock()
mock_response.text = '<p>Mistral generated content</p>'
mock_response.tokens_used = 500
mock_response = _make_mock_llm_response(tokens_used=500)
with patch(
'odoo.addons.itsulu_blog_publisher.services.ollama_provider'
@ -112,10 +130,10 @@ class TestLLMRouterProviderDispatch(TransactionCase):
return_value=mock_response,
) as mock_generate:
router = LLMRouter(self.env, provider='ollama', model='mistral')
result = router.generate(prompt='Write a blog post about open source AI')
result = router.generate(topic='Write a blog post about open source AI')
mock_generate.assert_called_once()
self.assertTrue(result.text)
self.assertTrue(result.body_html)
def test_unknown_provider_raises_user_error(self):
"""
@ -126,9 +144,9 @@ class TestLLMRouterProviderDispatch(TransactionCase):
with self.assertRaises(UserError) as ctx:
router = LLMRouter(self.env, provider='unknown_provider', model='some-model')
router.generate(prompt='This should fail')
router.generate(topic='This should fail')
self.assertIn('provider not configured', str(ctx.exception).lower())
self.assertIn('not configured', str(ctx.exception).lower())
def test_missing_api_key_raises_user_error(self):
"""Router raises UserError when required API key param is absent."""
@ -139,7 +157,7 @@ class TestLLMRouterProviderDispatch(TransactionCase):
)
with self.assertRaises(UserError) as ctx:
router = LLMRouter(self.env, provider='anthropic', model='claude-sonnet-4-20250514')
router.generate(prompt='Fail fast')
router.generate(topic='Fail fast')
self.assertIn('api key', str(ctx.exception).lower())
# Restore for other tests
@ -166,9 +184,7 @@ class TestLLMRouterTokenLogging(TransactionCase):
tokens_used as a positive integer when the API returns usage data.
"""
from odoo.addons.itsulu_blog_publisher.services.llm_router import LLMRouter
mock_response = MagicMock()
mock_response.text = '<p>Content</p>'
mock_response.tokens_used = 1234
mock_response = _make_mock_llm_response(tokens_used=1234)
with patch(
'odoo.addons.itsulu_blog_publisher.services.anthropic_provider'
@ -176,7 +192,7 @@ class TestLLMRouterTokenLogging(TransactionCase):
return_value=mock_response,
):
router = LLMRouter(self.env, provider='anthropic', model='claude-sonnet-4-20250514')
result = router.generate(prompt='Token test')
result = router.generate(topic='Token test')
self.assertGreater(result.tokens_used, 0)
self.assertEqual(result.tokens_used, 1234)