The blog.post model from website_blog has various validation constraints that aren't relevant for testing. Using sudo() allows test records to be created with minimal required fields only.
110 lines
3.9 KiB
Python
110 lines
3.9 KiB
Python
# addons/itsulu_blog_publisher/tests/factories.py
|
|
"""
|
|
Test data factory for itsulu_blog_publisher.
|
|
Use this instead of demo data. Never rely on records seeded in another test.
|
|
"""
|
|
|
|
|
|
class BlogPublisherFactory:
|
|
def __init__(self, env):
|
|
self.env = env
|
|
self._counter = 0
|
|
|
|
def _seq(self):
|
|
self._counter += 1
|
|
return self._counter
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# Core Odoo blog records #
|
|
# ------------------------------------------------------------------ #
|
|
|
|
def blog(self, **kw):
|
|
defaults = {
|
|
'name': f'Test Blog {self._seq()}',
|
|
}
|
|
defaults.update(kw)
|
|
return self.env['blog.blog'].create(defaults)
|
|
|
|
def blog_tag(self, **kw):
|
|
defaults = {
|
|
'name': f'Test Tag {self._seq()}',
|
|
}
|
|
defaults.update(kw)
|
|
return self.env['blog.tag'].create(defaults)
|
|
|
|
def blog_post(self, blog=None, **kw):
|
|
blog = blog or self.blog()
|
|
defaults = {
|
|
'name': f'Test Post {self._seq()}',
|
|
'blog_id': blog.id,
|
|
'website_published': False,
|
|
'is_published': False,
|
|
'website_meta_title': '',
|
|
'website_meta_description': '',
|
|
'website_meta_keywords': '',
|
|
}
|
|
defaults.update(kw)
|
|
# Use sudo() to bypass any validation that might fail in tests
|
|
return self.env['blog.post'].sudo().create(defaults)
|
|
|
|
# ------------------------------------------------------------------ #
|
|
# itsulu_blog_publisher models #
|
|
# ------------------------------------------------------------------ #
|
|
|
|
def blog_topic(self, **kw):
|
|
"""itsulu.blog.topic — a planned topic in the queue."""
|
|
defaults = {
|
|
'name': f'Test Topic {self._seq()}',
|
|
'priority': 'normal',
|
|
'state': 'pending',
|
|
'notes': '',
|
|
}
|
|
defaults.update(kw)
|
|
return self.env['itsulu.blog.topic'].create(defaults)
|
|
|
|
def blog_schedule(self, blog=None, **kw):
|
|
"""itsulu.blog.schedule — a cron slot configuration."""
|
|
blog = blog or self.blog()
|
|
defaults = {
|
|
'name': f'Test Schedule {self._seq()}',
|
|
'slot': 'morning',
|
|
'trigger_time': 8.0, # 08:00
|
|
'active': True,
|
|
'blog_id': blog.id,
|
|
'llm_provider': 'anthropic',
|
|
'llm_model': 'claude-sonnet-4-20250514',
|
|
'auto_publish': True,
|
|
}
|
|
defaults.update(kw)
|
|
return self.env['itsulu.blog.schedule'].create(defaults)
|
|
|
|
def generation_log(self, blog_post=None, **kw):
|
|
"""itsulu.blog.generation.log — one attempt record."""
|
|
defaults = {
|
|
'state': 'success',
|
|
'trigger_source': 'manual',
|
|
'llm_provider': 'anthropic',
|
|
'llm_model': 'claude-sonnet-4-20250514',
|
|
'tokens_used': 1500,
|
|
'duration_seconds': 12.0,
|
|
'error_message': '',
|
|
'blog_post_id': blog_post.id if blog_post else False,
|
|
}
|
|
defaults.update(kw)
|
|
return self.env['itsulu.blog.generation.log'].create(defaults)
|
|
|
|
def blog_post_social(self, blog_post=None, **kw):
|
|
"""itsulu.blog.post.social — social media copy for one post."""
|
|
blog_post = blog_post or self.blog_post()
|
|
defaults = {
|
|
'blog_post_id': blog_post.id,
|
|
'twitter_post_a': 'Twitter copy A placeholder.',
|
|
'twitter_post_b': 'Twitter copy B placeholder.',
|
|
'bluesky_post_a': 'BlueSky copy A placeholder.',
|
|
'bluesky_post_b': 'BlueSky copy B placeholder.',
|
|
'mastodon_post': 'Mastodon copy placeholder.',
|
|
'linkedin_post': 'LinkedIn copy placeholder.',
|
|
'sources_referenced': '',
|
|
}
|
|
defaults.update(kw)
|
|
return self.env['itsulu.blog.post.social'].create(defaults)
|