""" Unit tests for site assignment """ import pytest from unittest.mock import Mock, MagicMock, patch from src.generation.site_assignment import assign_sites_to_batch, _get_keyword_sites from src.database.models import GeneratedContent, SiteDeployment from src.generation.job_config import Job class TestGetKeywordSites: """Tests for _get_keyword_sites helper""" def test_exact_match(self): site1 = Mock(spec=SiteDeployment) site1.site_name = "engine-repair-abc" site2 = Mock(spec=SiteDeployment) site2.site_name = "car-maintenance-xyz" result = _get_keyword_sites([site1, site2], "engine repair") assert len(result) == 1 assert result[0] == site1 def test_partial_match(self): site1 = Mock(spec=SiteDeployment) site1.site_name = "my-engine-site" result = _get_keyword_sites([site1], "engine") assert len(result) == 1 def test_no_match(self): site1 = Mock(spec=SiteDeployment) site1.site_name = "random-site-123" result = _get_keyword_sites([site1], "engine repair") assert len(result) == 0 class TestAssignSitesToBatch: """Tests for assign_sites_to_batch function""" def test_assign_with_sufficient_sites(self): content1 = Mock(spec=GeneratedContent) content1.id = 1 content1.tier = "tier1" content1.keyword = "engine" content1.site_deployment_id = None content2 = Mock(spec=GeneratedContent) content2.id = 2 content2.tier = "tier2" content2.keyword = "car" content2.site_deployment_id = None site1 = Mock(spec=SiteDeployment) site1.id = 10 site1.site_name = "site1" site1.custom_hostname = "www.site1.com" site2 = Mock(spec=SiteDeployment) site2.id = 20 site2.site_name = "site2" site2.pull_zone_bcdn_hostname = "site2.b-cdn.net" job = Job( project_id=1, tiers={}, deployment_targets=None, tier1_preferred_sites=None, auto_create_sites=False, create_sites_for_keywords=None ) site_repo = Mock() site_repo.get_all.return_value = [site1, site2] site_repo.session = Mock() bunny_client = Mock() assign_sites_to_batch( [content1, content2], job, site_repo, bunny_client, "test-project" ) assert content1.site_deployment_id is not None assert content2.site_deployment_id is not None assert content1.site_deployment_id != content2.site_deployment_id site_repo.session.commit.assert_called_once() def test_assign_tier1_preferred_sites(self): content1 = Mock(spec=GeneratedContent) content1.id = 1 content1.tier = "tier1" content1.keyword = "test" content1.site_deployment_id = None preferred_site = Mock(spec=SiteDeployment) preferred_site.id = 10 preferred_site.site_name = "preferred" preferred_site.custom_hostname = "www.preferred.com" preferred_site.pull_zone_bcdn_hostname = "preferred.b-cdn.net" other_site = Mock(spec=SiteDeployment) other_site.id = 20 other_site.site_name = "other" other_site.custom_hostname = None other_site.pull_zone_bcdn_hostname = "other.b-cdn.net" job = Job( project_id=1, tiers={}, deployment_targets=None, tier1_preferred_sites=["www.preferred.com"], auto_create_sites=False, create_sites_for_keywords=None ) site_repo = Mock() site_repo.get_all.return_value = [preferred_site, other_site] site_repo.get_by_hostname.return_value = preferred_site site_repo.get_by_bcdn_hostname.return_value = None site_repo.session = Mock() bunny_client = Mock() assign_sites_to_batch([content1], job, site_repo, bunny_client, "test") assert content1.site_deployment_id == 10 def test_skip_already_assigned_articles(self): content1 = Mock(spec=GeneratedContent) content1.id = 1 content1.tier = "tier1" content1.keyword = "test" content1.site_deployment_id = 5 site_repo = Mock() site_repo.get_all.return_value = [] site_repo.session = Mock() job = Job( project_id=1, tiers={}, deployment_targets=None, auto_create_sites=False ) bunny_client = Mock() assign_sites_to_batch([content1], job, site_repo, bunny_client, "test") assert content1.site_deployment_id == 5 site_repo.session.add.assert_not_called() def test_error_insufficient_sites_without_auto_create(self): content1 = Mock(spec=GeneratedContent) content1.id = 1 content1.tier = "tier1" content1.keyword = "test" content1.site_deployment_id = None job = Job( project_id=1, tiers={}, deployment_targets=None, auto_create_sites=False, create_sites_for_keywords=None ) site_repo = Mock() site_repo.get_all.return_value = [] site_repo.session = Mock() bunny_client = Mock() with pytest.raises(ValueError, match="Insufficient sites"): assign_sites_to_batch([content1], job, site_repo, bunny_client, "test") @patch('src.generation.site_assignment.create_generic_sites') def test_auto_create_sites_when_insufficient(self, mock_create): content1 = Mock(spec=GeneratedContent) content1.id = 1 content1.tier = "tier1" content1.keyword = "test" content1.site_deployment_id = None new_site = Mock(spec=SiteDeployment) new_site.id = 100 new_site.site_name = "auto-created" new_site.pull_zone_bcdn_hostname = "auto.b-cdn.net" mock_create.return_value = [new_site] job = Job( project_id=1, tiers={}, deployment_targets=None, auto_create_sites=True, create_sites_for_keywords=None ) site_repo = Mock() site_repo.get_all.return_value = [] site_repo.session = Mock() bunny_client = Mock() assign_sites_to_batch([content1], job, site_repo, bunny_client, "test-project") assert content1.site_deployment_id == 100 mock_create.assert_called_once_with( count=1, project_keyword="test-project", bunny_client=bunny_client, site_repo=site_repo, region="DE" ) @patch('src.generation.site_assignment.provision_keyword_sites') def test_create_keyword_sites_before_assignment(self, mock_provision): keyword_site = Mock(spec=SiteDeployment) keyword_site.id = 50 keyword_site.site_name = "engine-repair-abc" mock_provision.return_value = [keyword_site] content1 = Mock(spec=GeneratedContent) content1.id = 1 content1.tier = "tier1" content1.keyword = "engine" content1.site_deployment_id = None job = Job( project_id=1, tiers={}, deployment_targets=None, auto_create_sites=False, create_sites_for_keywords=[{"keyword": "engine repair", "count": 1}] ) site_repo = Mock() site_repo.get_all.return_value = [keyword_site] site_repo.session = Mock() bunny_client = Mock() assign_sites_to_batch([content1], job, site_repo, bunny_client, "test") mock_provision.assert_called_once() assert content1.site_deployment_id is not None