test(02-03): add failing tests for ZhihuAdapter
- Test answer content extraction - Test zhuanlan (article) content extraction - Test cookie-based authentication - Test login page detection - Test AuthError handling for missing/expired cookies Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
"""Tests for ZhihuAdapter
|
||||
|
||||
Tests cover:
|
||||
- Answer content extraction
|
||||
- Zhuanlan (article) content extraction
|
||||
- Cookie-based authentication
|
||||
- Login page detection
|
||||
- AuthError handling
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, patch, PropertyMock
|
||||
import asyncio
|
||||
|
||||
from kb_pipeline.platforms.zhihu import ZhihuAdapter
|
||||
from kb_pipeline.errors import AuthError
|
||||
|
||||
|
||||
class TestZhihuAdapterAnswerContent:
|
||||
"""Tests for ZhihuAdapter answer extraction"""
|
||||
|
||||
def test_get_content_type_answer(self):
|
||||
"""Test content type detection for answer URLs"""
|
||||
adapter = ZhihuAdapter()
|
||||
adapter._cookie = "test" # Avoid config loading
|
||||
|
||||
assert adapter.get_content_type("https://www.zhihu.com/question/123456/answer/789012") == "answer"
|
||||
assert adapter.get_content_type("https://zhihu.com/question/123/answer/456") == "answer"
|
||||
|
||||
def test_get_content_type_zhuanlan(self):
|
||||
"""Test content type detection for zhuanlan URLs"""
|
||||
adapter = ZhihuAdapter()
|
||||
adapter._cookie = "test" # Avoid config loading
|
||||
|
||||
assert adapter.get_content_type("https://zhuanlan.zhihu.com/p/123456") == "zhuanlan"
|
||||
assert adapter.get_content_type("https://zhuanlan.zhihu.com/p/abc123") == "zhuanlan"
|
||||
|
||||
def test_get_content_type_unknown(self):
|
||||
"""Test content type detection for unknown URLs"""
|
||||
adapter = ZhihuAdapter()
|
||||
adapter._cookie = "test" # Avoid config loading
|
||||
|
||||
assert adapter.get_content_type("https://www.zhihu.com/question/123456") == "unknown"
|
||||
assert adapter.get_content_type("https://www.zhihu.com/") == "unknown"
|
||||
assert adapter.get_content_type("https://example.com") == "unknown"
|
||||
|
||||
def test_get_output_filename(self):
|
||||
"""Test output filename generation"""
|
||||
adapter = ZhihuAdapter()
|
||||
adapter._cookie = "test" # Avoid config loading
|
||||
|
||||
assert adapter.get_output_filename("789012", "answer", "metadata.json") == "zhihu_789012_metadata.json"
|
||||
assert adapter.get_output_filename("123456", "zhuanlan", "content.md") == "zhihu_123456_content.md"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fetch_metadata_answer(self, mock_zhihu_answer_result):
|
||||
"""Test fetching answer metadata"""
|
||||
adapter = ZhihuAdapter()
|
||||
adapter._cookie = "test_cookie" # Set cookie directly
|
||||
|
||||
with patch.object(adapter, '_extract_with_playwright', return_value=mock_zhihu_answer_result):
|
||||
metadata = await adapter.fetch_metadata("789012", "answer")
|
||||
|
||||
assert metadata["title"] == "Test Question Title"
|
||||
assert metadata["author"] == "Test Author"
|
||||
assert metadata["type"] == "answer"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fetch_content_answer(self, mock_zhihu_answer_result):
|
||||
"""Test fetching answer content as Markdown"""
|
||||
adapter = ZhihuAdapter()
|
||||
adapter._cookie = "test_cookie" # Set cookie directly
|
||||
|
||||
with patch.object(adapter, '_extract_with_playwright', return_value=mock_zhihu_answer_result):
|
||||
content = await adapter.fetch_content("789012", "answer")
|
||||
|
||||
assert "---" in content # YAML frontmatter
|
||||
assert "title:" in content
|
||||
assert "Test Question Title" in content
|
||||
assert "This is the answer content" in content
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fetch_metadata_no_cookie_raises_auth_error(self):
|
||||
"""Test that missing cookie raises AuthError"""
|
||||
adapter = ZhihuAdapter()
|
||||
adapter._cookie = "" # Empty cookie
|
||||
|
||||
with pytest.raises(AuthError) as exc_info:
|
||||
await adapter.fetch_metadata("789012", "answer")
|
||||
|
||||
assert exc_info.value.auth_type == "zhihu_cookie"
|
||||
|
||||
|
||||
class TestZhihuAdapterZhuanlanContent:
|
||||
"""Tests for ZhihuAdapter zhuanlan (article) extraction"""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fetch_metadata_zhuanlan(self, mock_zhihu_zhuanlan_result):
|
||||
"""Test fetching zhuanlan metadata"""
|
||||
adapter = ZhihuAdapter()
|
||||
adapter._cookie = "test_cookie" # Set cookie directly
|
||||
|
||||
with patch.object(adapter, '_extract_with_playwright', return_value=mock_zhihu_zhuanlan_result):
|
||||
metadata = await adapter.fetch_metadata("123456", "zhuanlan")
|
||||
|
||||
assert metadata["title"] == "Test Article Title"
|
||||
assert metadata["author"] == "Test Author"
|
||||
assert metadata["type"] == "zhuanlan"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fetch_content_zhuanlan(self, mock_zhihu_zhuanlan_result):
|
||||
"""Test fetching zhuanlan content as Markdown"""
|
||||
adapter = ZhihuAdapter()
|
||||
adapter._cookie = "test_cookie" # Set cookie directly
|
||||
|
||||
with patch.object(adapter, '_extract_with_playwright', return_value=mock_zhihu_zhuanlan_result):
|
||||
content = await adapter.fetch_content("123456", "zhuanlan")
|
||||
|
||||
assert "---" in content # YAML frontmatter
|
||||
assert "title:" in content
|
||||
assert "Test Article Title" in content
|
||||
assert "This is the article content" in content
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_detect_login_page_raises_auth_error(self):
|
||||
"""Test that login page detection raises AuthError"""
|
||||
adapter = ZhihuAdapter()
|
||||
adapter._cookie = "expired_cookie" # Set cookie directly
|
||||
|
||||
# Simulate login page response (empty content or login title)
|
||||
login_page_result = {
|
||||
"type": "answer",
|
||||
"title": "登录 - 知乎",
|
||||
"content": "",
|
||||
"content_markdown": "",
|
||||
}
|
||||
|
||||
with patch.object(adapter, '_extract_with_playwright', return_value=login_page_result):
|
||||
with pytest.raises(AuthError) as exc_info:
|
||||
await adapter.fetch_metadata("789012", "answer")
|
||||
|
||||
assert exc_info.value.auth_type == "zhihu_cookie"
|
||||
assert "过期" in str(exc_info.value.cause) or "expired" in str(exc_info.value.cause).lower()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_detect_short_content_raises_auth_error(self):
|
||||
"""Test that very short content (< 100 chars) raises AuthError"""
|
||||
adapter = ZhihuAdapter()
|
||||
adapter._cookie = "test_cookie"
|
||||
|
||||
# Simulate response with very short content
|
||||
short_content_result = {
|
||||
"type": "answer",
|
||||
"title": "Some Title",
|
||||
"content": "x", # Very short content
|
||||
"content_markdown": "",
|
||||
}
|
||||
|
||||
with patch.object(adapter, '_extract_with_playwright', return_value=short_content_result):
|
||||
with pytest.raises(AuthError) as exc_info:
|
||||
await adapter.fetch_metadata("789012", "answer")
|
||||
|
||||
assert exc_info.value.auth_type == "zhihu_cookie"
|
||||
|
||||
|
||||
class TestZhihuAdapterCookieHandling:
|
||||
"""Tests for cookie handling"""
|
||||
|
||||
def test_cookie_from_settings(self):
|
||||
"""Test cookie is loaded from settings"""
|
||||
with patch('kb_pipeline.platforms.zhihu.get_settings') as mock_settings:
|
||||
mock_secret = MagicMock()
|
||||
mock_secret.get_secret_value.return_value = "test_cookie_value"
|
||||
mock_settings.return_value.zhihu_cookie = mock_secret
|
||||
|
||||
adapter = ZhihuAdapter()
|
||||
assert adapter.cookie == "test_cookie_value"
|
||||
|
||||
def test_platform_constant(self):
|
||||
"""Test PLATFORM constant"""
|
||||
adapter = ZhihuAdapter()
|
||||
adapter._cookie = "test" # Avoid config loading
|
||||
assert adapter.PLATFORM == "zhihu"
|
||||
Reference in New Issue
Block a user