# addons/itsulu_blog_publisher/tests/test_blog_topic.py """ Tests for models/blog_topic.py Behaviour: topic queue management — create, prioritise, mark used, pop next topic, fall back gracefully when queue is empty. RED PHASE — all tests FAIL until itsulu.blog.topic model exists. """ from odoo.tests import TransactionCase, tagged from odoo.exceptions import ValidationError from .factories import BlogPublisherFactory @tagged('post_install', '-at_install', 'itsulu_blog_publisher', 'blog_topic') class TestBlogTopicQueueManagement(TransactionCase): """Verify that the topic queue picks topics in priority order.""" @classmethod def setUpClass(cls): super().setUpClass() cls.factory = BlogPublisherFactory(cls.env) def test_topic_is_created_with_pending_state(self): """ 1. Behaviour: newly created topic starts in state='pending' 2. ARRANGE: nothing — default factory values 3. ACT: create a topic record 4. ASSERT: state == 'pending' 5. FAIL reason: model itsulu.blog.topic does not exist """ # ARRANGE + ACT topic = self.factory.blog_topic(name='AI Ethics in Healthcare') # ASSERT self.assertEqual(topic.state, 'pending') def test_get_next_topic_returns_highest_priority_pending_topic(self): """ get_next_topic() on the model returns the pending topic with the highest priority (urgent > high > normal > low). """ # ARRANGE low = self.factory.blog_topic(name='Low priority topic', priority='low') normal = self.factory.blog_topic(name='Normal priority topic', priority='normal') urgent = self.factory.blog_topic(name='Urgent topic', priority='urgent') high = self.factory.blog_topic(name='High priority topic', priority='high') # ACT next_topic = self.env['itsulu.blog.topic'].get_next_topic() # ASSERT self.assertEqual(next_topic.id, urgent.id, "get_next_topic() must return the urgent-priority topic first") def test_get_next_topic_returns_none_when_queue_is_empty(self): """get_next_topic() returns False (empty recordset) when no pending topics exist.""" # ARRANGE — mark all pending topics as used to clear the queue self.env['itsulu.blog.topic'].search([('state', '=', 'pending')]).write( {'state': 'used'} ) # ACT result = self.env['itsulu.blog.topic'].get_next_topic() # ASSERT self.assertFalse(result, "get_next_topic() must return empty recordset when queue is empty") def test_mark_topic_as_used_changes_state(self): """Calling topic.mark_used() sets state to 'used'.""" # ARRANGE topic = self.factory.blog_topic(name='DevOps best practices') # ACT topic.mark_used() # ASSERT self.assertEqual(topic.state, 'used') def test_used_topic_is_excluded_from_next_topic_selection(self): """A used topic is never returned by get_next_topic().""" # ARRANGE used_topic = self.factory.blog_topic( name='Already published topic', priority='urgent', state='used' ) pending_topic = self.factory.blog_topic( name='Not yet published', priority='normal', state='pending' ) # ACT next_topic = self.env['itsulu.blog.topic'].get_next_topic() # ASSERT self.assertNotEqual(next_topic.id, used_topic.id) self.assertEqual(next_topic.id, pending_topic.id) def test_topic_name_cannot_be_empty(self): """Creating a topic with an empty name raises ValidationError.""" with self.assertRaises(ValidationError): self.factory.blog_topic(name='') def test_topic_can_be_linked_to_a_specific_blog(self): """A topic can optionally specify which blog it should be published to.""" # ARRANGE blog = self.factory.blog(name='ITSulu Insights') # ACT topic = self.factory.blog_topic( name='Kubernetes for SMBs', blog_id=blog.id, ) # ASSERT self.assertEqual(topic.blog_id.id, blog.id)