Format tests
This commit is contained in:
		
							parent
							
								
									c1cb0f46a4
								
							
						
					
					
						commit
						fef5023d74
					
				| 
						 | 
					@ -24,17 +24,19 @@ def level_to_int(logger, method_name, event_dict):
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
    return event_dict
 | 
					    return event_dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture(autouse=True, scope="session")
 | 
					@pytest.fixture(autouse=True, scope="session")
 | 
				
			||||||
def configure_structlog():
 | 
					def configure_structlog():
 | 
				
			||||||
    import tenacity
 | 
					    import tenacity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    logging.basicConfig(level=logging.DEBUG)
 | 
					    logging.basicConfig(level=logging.DEBUG)
 | 
				
			||||||
    structlog.configure(
 | 
					    structlog.configure(
 | 
				
			||||||
        processors=[
 | 
					        processors=[
 | 
				
			||||||
            level_to_int,
 | 
					            level_to_int,
 | 
				
			||||||
            structlog.processors.TimeStamper(fmt="iso"),
 | 
					            structlog.processors.TimeStamper(fmt="iso"),
 | 
				
			||||||
            structlog.dev.ConsoleRenderer()
 | 
					            structlog.dev.ConsoleRenderer(),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        wrapper_class=structlog.make_filtering_bound_logger(logging.DEBUG)
 | 
					        wrapper_class=structlog.make_filtering_bound_logger(logging.DEBUG),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    tenacity.logger = structlog.get_logger("tenacity")
 | 
					    tenacity.logger = structlog.get_logger("tenacity")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -185,7 +185,11 @@ class TestLLMProviderAdapter:
 | 
				
			||||||
        long_text = "word " * 2000
 | 
					        long_text = "word " * 2000
 | 
				
			||||||
        with patch.object(adapter, "_check_rpm_limit"):
 | 
					        with patch.object(adapter, "_check_rpm_limit"):
 | 
				
			||||||
            with patch.object(adapter, "count_tokens", return_value=50000):
 | 
					            with patch.object(adapter, "count_tokens", return_value=50000):
 | 
				
			||||||
                with patch.object(adapter, "_make_completion_request", side_effect=LLMTokenLimitError("Token limit exceeded")):
 | 
					                with patch.object(
 | 
				
			||||||
 | 
					                    adapter,
 | 
				
			||||||
 | 
					                    "_make_completion_request",
 | 
				
			||||||
 | 
					                    side_effect=LLMTokenLimitError("Token limit exceeded"),
 | 
				
			||||||
 | 
					                ):
 | 
				
			||||||
                    with pytest.raises(LLMTokenLimitError):
 | 
					                    with pytest.raises(LLMTokenLimitError):
 | 
				
			||||||
                        await adapter.simplify_text("Test", long_text, "template")
 | 
					                        await adapter.simplify_text("Test", long_text, "template")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -193,7 +197,9 @@ class TestLLMProviderAdapter:
 | 
				
			||||||
    async def test_simplify_text_success(self, test_config, mock_openai_response):
 | 
					    async def test_simplify_text_success(self, test_config, mock_openai_response):
 | 
				
			||||||
        adapter = LLMProviderAdapter(test_config)
 | 
					        adapter = LLMProviderAdapter(test_config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with patch.object(adapter.client.chat.completions, "create", new_callable=AsyncMock) as mock_create:
 | 
					        with patch.object(
 | 
				
			||||||
 | 
					            adapter.client.chat.completions, "create", new_callable=AsyncMock
 | 
				
			||||||
 | 
					        ) as mock_create:
 | 
				
			||||||
            mock_create.return_value = mock_openai_response
 | 
					            mock_create.return_value = mock_openai_response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with patch.object(adapter, "_check_rpm_limit"):
 | 
					            with patch.object(adapter, "_check_rpm_limit"):
 | 
				
			||||||
| 
						 | 
					@ -230,9 +236,13 @@ class TestLLMProviderAdapter:
 | 
				
			||||||
                **{**kwargs, "before_sleep": fixed_before_sleep_log(good_logger, logging.WARNING)}
 | 
					                **{**kwargs, "before_sleep": fixed_before_sleep_log(good_logger, logging.WARNING)}
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with patch.object(adapter.client.chat.completions, "create", new_callable=AsyncMock) as mock_create:
 | 
					            with patch.object(
 | 
				
			||||||
 | 
					                adapter.client.chat.completions, "create", new_callable=AsyncMock
 | 
				
			||||||
 | 
					            ) as mock_create:
 | 
				
			||||||
                mock_response = MagicMock()
 | 
					                mock_response = MagicMock()
 | 
				
			||||||
                mock_create.side_effect = RateLimitError("Rate limit exceeded", response=mock_response, body=None)
 | 
					                mock_create.side_effect = RateLimitError(
 | 
				
			||||||
 | 
					                    "Rate limit exceeded", response=mock_response, body=None
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
                with patch.object(adapter, "_check_rpm_limit"):
 | 
					                with patch.object(adapter, "_check_rpm_limit"):
 | 
				
			||||||
                    with pytest.raises(LLMRateLimitError):
 | 
					                    with pytest.raises(LLMRateLimitError):
 | 
				
			||||||
                        await adapter.simplify_text(
 | 
					                        await adapter.simplify_text(
 | 
				
			||||||
| 
						 | 
					@ -272,7 +282,9 @@ class TestLLMProviderAdapter:
 | 
				
			||||||
    async def test_health_check_success(self, test_config, mock_openai_response):
 | 
					    async def test_health_check_success(self, test_config, mock_openai_response):
 | 
				
			||||||
        adapter = LLMProviderAdapter(test_config)
 | 
					        adapter = LLMProviderAdapter(test_config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with patch.object(adapter.client.chat.completions, "create", new_callable=AsyncMock) as mock_create:
 | 
					        with patch.object(
 | 
				
			||||||
 | 
					            adapter.client.chat.completions, "create", new_callable=AsyncMock
 | 
				
			||||||
 | 
					        ) as mock_create:
 | 
				
			||||||
            mock_create.return_value = mock_openai_response
 | 
					            mock_create.return_value = mock_openai_response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            result = await adapter.health_check()
 | 
					            result = await adapter.health_check()
 | 
				
			||||||
| 
						 | 
					@ -281,7 +293,9 @@ class TestLLMProviderAdapter:
 | 
				
			||||||
    @pytest.mark.asyncio
 | 
					    @pytest.mark.asyncio
 | 
				
			||||||
    async def test_health_check_failure(self, test_config):
 | 
					    async def test_health_check_failure(self, test_config):
 | 
				
			||||||
        adapter = LLMProviderAdapter(test_config)
 | 
					        adapter = LLMProviderAdapter(test_config)
 | 
				
			||||||
        with patch.object(adapter.client.chat.completions, "create", new_callable=AsyncMock) as mock_create:
 | 
					        with patch.object(
 | 
				
			||||||
 | 
					            adapter.client.chat.completions, "create", new_callable=AsyncMock
 | 
				
			||||||
 | 
					        ) as mock_create:
 | 
				
			||||||
            mock_request = MagicMock()
 | 
					            mock_request = MagicMock()
 | 
				
			||||||
            mock_create.side_effect = APIError("API Error", body=None, request=mock_request)
 | 
					            mock_create.side_effect = APIError("API Error", body=None, request=mock_request)
 | 
				
			||||||
            result = await adapter.health_check()
 | 
					            result = await adapter.health_check()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -223,7 +223,6 @@ class TestAsyncOperations:
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class TestSystemIntegration:
 | 
					class TestSystemIntegration:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @pytest.mark.asyncio
 | 
					    @pytest.mark.asyncio
 | 
				
			||||||
| 
						 | 
					@ -281,7 +280,9 @@ class TestSystemIntegration:
 | 
				
			||||||
                mock_llm_instance.simplify_text.return_value = ("Упрощённый текст", 100, 50)
 | 
					                mock_llm_instance.simplify_text.return_value = ("Упрощённый текст", 100, 50)
 | 
				
			||||||
                mock_llm_instance.count_tokens.return_value = 100
 | 
					                mock_llm_instance.count_tokens.return_value = 100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False, encoding="utf-8") as f:
 | 
					                with tempfile.NamedTemporaryFile(
 | 
				
			||||||
 | 
					                    mode="w", suffix=".txt", delete=False, encoding="utf-8"
 | 
				
			||||||
 | 
					                ) as f:
 | 
				
			||||||
                    f.write("### role: user\n{wiki_source_text}")
 | 
					                    f.write("### role: user\n{wiki_source_text}")
 | 
				
			||||||
                    test_config.prompt_template_path = f.name
 | 
					                    test_config.prompt_template_path = f.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -364,7 +365,9 @@ class TestSystemIntegration:
 | 
				
			||||||
                mock_llm_instance.simplify_text.side_effect = delayed_simplify
 | 
					                mock_llm_instance.simplify_text.side_effect = delayed_simplify
 | 
				
			||||||
                mock_llm_instance.count_tokens.return_value = 100
 | 
					                mock_llm_instance.count_tokens.return_value = 100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False, encoding="utf-8") as f:
 | 
					                with tempfile.NamedTemporaryFile(
 | 
				
			||||||
 | 
					                    mode="w", suffix=".txt", delete=False, encoding="utf-8"
 | 
				
			||||||
 | 
					                ) as f:
 | 
				
			||||||
                    f.write("### role: user\n{wiki_source_text}")
 | 
					                    f.write("### role: user\n{wiki_source_text}")
 | 
				
			||||||
                    test_config.prompt_template_path = f.name
 | 
					                    test_config.prompt_template_path = f.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,14 +76,12 @@ class TestAppConfig:
 | 
				
			||||||
    def test_app_config_defaults(self):
 | 
					    def test_app_config_defaults(self):
 | 
				
			||||||
        from pathlib import Path
 | 
					        from pathlib import Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
        import os
 | 
					        import os
 | 
				
			||||||
        from unittest.mock import patch
 | 
					        from unittest.mock import patch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with patch.dict(os.environ, {}, clear=True):
 | 
					        with patch.dict(os.environ, {}, clear=True):
 | 
				
			||||||
            config = AppConfig(openai_api_key="test-key")
 | 
					            config = AppConfig(openai_api_key="test-key")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
        assert isinstance(config.db_path, str)
 | 
					        assert isinstance(config.db_path, str)
 | 
				
			||||||
        assert Path(config.db_path).suffix == ".db"
 | 
					        assert Path(config.db_path).suffix == ".db"
 | 
				
			||||||
        assert isinstance(config.openai_model, str)
 | 
					        assert isinstance(config.openai_model, str)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,7 +59,6 @@ class TestArticleRepository:
 | 
				
			||||||
            raw_text="Test content",
 | 
					            raw_text="Test content",
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
        with pytest.raises(ValueError, match="уже существует"):
 | 
					        with pytest.raises(ValueError, match="уже существует"):
 | 
				
			||||||
            await repository.create_article(
 | 
					            await repository.create_article(
 | 
				
			||||||
                url=url,
 | 
					                url=url,
 | 
				
			||||||
| 
						 | 
					@ -79,7 +78,9 @@ class TestArticleRepository:
 | 
				
			||||||
        result = await repository.get_by_id(99999)
 | 
					        result = await repository.get_by_id(99999)
 | 
				
			||||||
        assert result is None
 | 
					        assert result is None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def test_get_by_url(self, repository: ArticleRepository, sample_article_in_db: ArticleDTO):
 | 
					    async def test_get_by_url(
 | 
				
			||||||
 | 
					        self, repository: ArticleRepository, sample_article_in_db: ArticleDTO
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        article = sample_article_in_db
 | 
					        article = sample_article_in_db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        retrieved = await repository.get_by_url(article.url)
 | 
					        retrieved = await repository.get_by_url(article.url)
 | 
				
			||||||
| 
						 | 
					@ -91,7 +92,9 @@ class TestArticleRepository:
 | 
				
			||||||
        result = await repository.get_by_url("https://ru.ruwiki.ru/wiki/NonExistent")
 | 
					        result = await repository.get_by_url("https://ru.ruwiki.ru/wiki/NonExistent")
 | 
				
			||||||
        assert result is None
 | 
					        assert result is None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def test_update_article(self, repository: ArticleRepository, sample_article_in_db: ArticleDTO):
 | 
					    async def test_update_article(
 | 
				
			||||||
 | 
					        self, repository: ArticleRepository, sample_article_in_db: ArticleDTO
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        article = sample_article_in_db
 | 
					        article = sample_article_in_db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        article.simplified_text = "Simplified content"
 | 
					        article.simplified_text = "Simplified content"
 | 
				
			||||||
| 
						 | 
					@ -158,7 +161,9 @@ class TestArticleRepository:
 | 
				
			||||||
        count = await repository.count_by_status(ArticleStatus.PENDING)
 | 
					        count = await repository.count_by_status(ArticleStatus.PENDING)
 | 
				
			||||||
        assert count == 2
 | 
					        assert count == 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def test_delete_article(self, repository: ArticleRepository, sample_article_in_db: ArticleDTO):
 | 
					    async def test_delete_article(
 | 
				
			||||||
 | 
					        self, repository: ArticleRepository, sample_article_in_db: ArticleDTO
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        article = sample_article_in_db
 | 
					        article = sample_article_in_db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        deleted = await repository.delete_article(article.id)
 | 
					        deleted = await repository.delete_article(article.id)
 | 
				
			||||||
| 
						 | 
					@ -191,7 +196,9 @@ class TestAsyncWriteQueue:
 | 
				
			||||||
        await queue.stop()
 | 
					        await queue.stop()
 | 
				
			||||||
        assert queue._worker_task.done()
 | 
					        assert queue._worker_task.done()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def test_update_article_operation(self, write_queue: AsyncWriteQueue, sample_article_in_db: ArticleDTO):
 | 
					    async def test_update_article_operation(
 | 
				
			||||||
 | 
					        self, write_queue: AsyncWriteQueue, sample_article_in_db: ArticleDTO
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        article = sample_article_in_db
 | 
					        article = sample_article_in_db
 | 
				
			||||||
        article.simplified_text = "Updated content"
 | 
					        article.simplified_text = "Updated content"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -202,7 +209,9 @@ class TestAsyncWriteQueue:
 | 
				
			||||||
        retrieved = await write_queue.repository.get_by_id(article.id)
 | 
					        retrieved = await write_queue.repository.get_by_id(article.id)
 | 
				
			||||||
        assert retrieved.simplified_text == "Updated content"
 | 
					        assert retrieved.simplified_text == "Updated content"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def test_update_from_result_success(self, write_queue: AsyncWriteQueue, sample_article_in_db: ArticleDTO):
 | 
					    async def test_update_from_result_success(
 | 
				
			||||||
 | 
					        self, write_queue: AsyncWriteQueue, sample_article_in_db: ArticleDTO
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        article = sample_article_in_db
 | 
					        article = sample_article_in_db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        result = ProcessingResult.success_result(
 | 
					        result = ProcessingResult.success_result(
 | 
				
			||||||
| 
						 | 
					@ -220,7 +229,9 @@ class TestAsyncWriteQueue:
 | 
				
			||||||
        assert updated_article.simplified_text == "Processed content"
 | 
					        assert updated_article.simplified_text == "Processed content"
 | 
				
			||||||
        assert updated_article.status == ArticleStatus.SIMPLIFIED
 | 
					        assert updated_article.status == ArticleStatus.SIMPLIFIED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def test_update_from_result_failure(self, write_queue: AsyncWriteQueue, sample_article_in_db: ArticleDTO):
 | 
					    async def test_update_from_result_failure(
 | 
				
			||||||
 | 
					        self, write_queue: AsyncWriteQueue, sample_article_in_db: ArticleDTO
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
        article = sample_article_in_db
 | 
					        article = sample_article_in_db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        result = ProcessingResult.failure_result(
 | 
					        result = ProcessingResult.failure_result(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue