""" Unit tests for deployment target assignment logic """ import pytest from unittest.mock import Mock, MagicMock from src.generation.deployment_assignment import ( resolve_hostname_to_id, validate_and_resolve_targets, assign_site_for_article ) from src.database.models import SiteDeployment class TestResolveHostnameToId: """Test resolve_hostname_to_id function""" def test_resolve_valid_hostname(self): """Test resolving a valid hostname""" mock_repo = Mock() mock_deployment = Mock(spec=SiteDeployment) mock_deployment.id = 5 mock_repo.get_by_hostname.return_value = mock_deployment result = resolve_hostname_to_id("www.example.com", mock_repo) assert result == 5 mock_repo.get_by_hostname.assert_called_once_with("www.example.com") def test_resolve_invalid_hostname(self): """Test resolving an invalid hostname returns None""" mock_repo = Mock() mock_repo.get_by_hostname.return_value = None result = resolve_hostname_to_id("nonexistent.com", mock_repo) assert result is None mock_repo.get_by_hostname.assert_called_once_with("nonexistent.com") class TestValidateAndResolveTargets: """Test validate_and_resolve_targets function""" def test_validate_empty_list(self): """Test validating an empty list returns empty dict""" mock_repo = Mock() result = validate_and_resolve_targets([], mock_repo) assert result == {} mock_repo.get_by_hostname.assert_not_called() def test_validate_all_valid_hostnames(self): """Test validating all valid hostnames""" mock_repo = Mock() def mock_get_by_hostname(hostname): deployments = { "www.domain1.com": Mock(id=1), "www.domain2.com": Mock(id=2), "www.domain3.com": Mock(id=3) } return deployments.get(hostname) mock_repo.get_by_hostname.side_effect = mock_get_by_hostname hostnames = ["www.domain1.com", "www.domain2.com", "www.domain3.com"] result = validate_and_resolve_targets(hostnames, mock_repo) assert result == { "www.domain1.com": 1, "www.domain2.com": 2, "www.domain3.com": 3 } assert mock_repo.get_by_hostname.call_count == 3 def test_validate_with_invalid_hostname(self): """Test validation fails with invalid hostname""" mock_repo = Mock() def mock_get_by_hostname(hostname): if hostname == "www.domain1.com": return Mock(id=1) return None mock_repo.get_by_hostname.side_effect = mock_get_by_hostname hostnames = ["www.domain1.com", "invalid.com"] with pytest.raises(ValueError) as exc_info: validate_and_resolve_targets(hostnames, mock_repo) assert "invalid.com" in str(exc_info.value) assert "not found in database" in str(exc_info.value) def test_validate_with_multiple_invalid_hostnames(self): """Test validation fails with multiple invalid hostnames""" mock_repo = Mock() mock_repo.get_by_hostname.return_value = None hostnames = ["invalid1.com", "invalid2.com", "invalid3.com"] with pytest.raises(ValueError) as exc_info: validate_and_resolve_targets(hostnames, mock_repo) error_msg = str(exc_info.value) assert "invalid1.com" in error_msg assert "invalid2.com" in error_msg assert "invalid3.com" in error_msg def test_validate_with_empty_string_hostname(self): """Test validation fails with empty string hostname""" mock_repo = Mock() hostnames = ["www.valid.com", ""] with pytest.raises(ValueError) as exc_info: validate_and_resolve_targets(hostnames, mock_repo) assert "Invalid hostname" in str(exc_info.value) def test_validate_with_non_string_hostname(self): """Test validation fails with non-string hostname""" mock_repo = Mock() hostnames = ["www.valid.com", 123] with pytest.raises(ValueError) as exc_info: validate_and_resolve_targets(hostnames, mock_repo) assert "Invalid hostname" in str(exc_info.value) class TestAssignSiteForArticle: """Test assign_site_for_article function""" def test_assign_with_empty_targets(self): """Test assignment with no targets returns None""" result = assign_site_for_article(0, {}) assert result is None result = assign_site_for_article(5, {}) assert result is None def test_assign_within_target_range(self): """Test assignment within target range""" resolved_targets = { "www.domain1.com": 5, "www.domain2.com": 8, "www.domain3.com": 12 } assert assign_site_for_article(0, resolved_targets) == 5 assert assign_site_for_article(1, resolved_targets) == 8 assert assign_site_for_article(2, resolved_targets) == 12 def test_assign_beyond_target_range(self): """Test assignment beyond target range returns None""" resolved_targets = { "www.domain1.com": 5, "www.domain2.com": 8, "www.domain3.com": 12 } assert assign_site_for_article(3, resolved_targets) is None assert assign_site_for_article(4, resolved_targets) is None assert assign_site_for_article(10, resolved_targets) is None def test_assign_single_target(self): """Test assignment with single target""" resolved_targets = {"www.domain1.com": 5} assert assign_site_for_article(0, resolved_targets) == 5 assert assign_site_for_article(1, resolved_targets) is None assert assign_site_for_article(2, resolved_targets) is None def test_assign_with_ten_articles_three_targets(self): """Test assignment scenario: 10 articles, 3 targets""" resolved_targets = { "www.domain1.com": 5, "www.domain2.com": 8, "www.domain3.com": 12 } results = [assign_site_for_article(i, resolved_targets) for i in range(10)] expected = [5, 8, 12, None, None, None, None, None, None, None] assert results == expected