Compare commits
2 commits
d231dce530
...
2dd0626a3a
| Author | SHA1 | Date | |
|---|---|---|---|
| 2dd0626a3a | |||
| f5d7a5ab5b |
2 changed files with 169 additions and 89 deletions
|
|
@ -6,7 +6,7 @@ from typing import Any, Awaitable, Callable, Optional, TypeVar
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from ..types.errors import NetworkError
|
from ..types.errors import NetworkError, AuthenticationError, GhostApiError, ValidationError
|
||||||
from .logging import get_logger
|
from .logging import get_logger
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
@ -22,6 +22,44 @@ class RetryConfig(BaseModel):
|
||||||
jitter: bool = True
|
jitter: bool = True
|
||||||
|
|
||||||
|
|
||||||
|
def _should_retry(exception: Exception) -> bool:
|
||||||
|
"""Determine if an exception should trigger a retry.
|
||||||
|
|
||||||
|
Only retry transient network errors, not client errors or authentication issues.
|
||||||
|
"""
|
||||||
|
# Retry network errors (connection issues, timeouts)
|
||||||
|
if isinstance(exception, NetworkError):
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Don't retry authentication errors - these need manual intervention
|
||||||
|
if isinstance(exception, AuthenticationError):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Don't retry validation errors - the request is malformed
|
||||||
|
if isinstance(exception, ValidationError):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# For Ghost API errors, only retry 5xx server errors, not 4xx client errors
|
||||||
|
if isinstance(exception, GhostApiError):
|
||||||
|
# Check if the error context indicates a server error (5xx)
|
||||||
|
if exception.context and "HTTP 5" in exception.context:
|
||||||
|
return True
|
||||||
|
# Check if it's a rate limiting error (429) - should be retried
|
||||||
|
if exception.context and "HTTP 429" in exception.context:
|
||||||
|
return True
|
||||||
|
# All other Ghost API errors (4xx) should not be retried
|
||||||
|
return False
|
||||||
|
|
||||||
|
# For unknown exceptions, be conservative and retry (could be network issues)
|
||||||
|
# but log a warning so we can identify what should/shouldn't be retried
|
||||||
|
logger.warning(
|
||||||
|
"Unknown exception type encountered in retry logic",
|
||||||
|
exception_type=type(exception).__name__,
|
||||||
|
exception=str(exception)
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def with_retry(
|
async def with_retry(
|
||||||
operation: Callable[[], Awaitable[T]],
|
operation: Callable[[], Awaitable[T]],
|
||||||
config: Optional[RetryConfig] = None,
|
config: Optional[RetryConfig] = None,
|
||||||
|
|
@ -39,6 +77,17 @@ async def with_retry(
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
last_exception = e
|
last_exception = e
|
||||||
|
|
||||||
|
# Check if this exception should trigger a retry
|
||||||
|
if not _should_retry(e):
|
||||||
|
logger.debug(
|
||||||
|
"Exception not suitable for retry, failing immediately",
|
||||||
|
attempt=attempt,
|
||||||
|
exception_type=type(e).__name__,
|
||||||
|
error=str(e),
|
||||||
|
request_id=request_id,
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
if attempt == config.max_retries:
|
if attempt == config.max_retries:
|
||||||
logger.error(
|
logger.error(
|
||||||
"Operation failed after all retries",
|
"Operation failed after all retries",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"""End-to-end tests for Ghost pages functionality."""
|
"""End-to-end tests for Ghost pages functionality."""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from .conftest import BaseE2ETest
|
from .conftest import BaseE2ETest
|
||||||
|
|
@ -10,12 +11,10 @@ from .conftest import BaseE2ETest
|
||||||
class TestPagesContentAPIE2E(BaseE2ETest):
|
class TestPagesContentAPIE2E(BaseE2ETest):
|
||||||
"""Test pages Content API functionality end-to-end."""
|
"""Test pages Content API functionality end-to-end."""
|
||||||
|
|
||||||
async def test_get_pages(self, mcp_server, sample_page):
|
async def test_get_pages(self, mcp_server, sample_page): # noqa: ARG002
|
||||||
"""Test getting pages."""
|
"""Test getting pages."""
|
||||||
from ghost_mcp.tools.content.pages import get_pages
|
|
||||||
|
|
||||||
# Get pages
|
# Get pages
|
||||||
result = await get_pages()
|
result = await self.call_mcp_tool(mcp_server, "get_pages")
|
||||||
response = json.loads(result)
|
response = json.loads(result)
|
||||||
|
|
||||||
# Verify response structure
|
# Verify response structure
|
||||||
|
|
@ -25,10 +24,8 @@ class TestPagesContentAPIE2E(BaseE2ETest):
|
||||||
|
|
||||||
async def test_get_pages_with_pagination(self, mcp_server):
|
async def test_get_pages_with_pagination(self, mcp_server):
|
||||||
"""Test getting pages with pagination parameters."""
|
"""Test getting pages with pagination parameters."""
|
||||||
from ghost_mcp.tools.content.pages import get_pages
|
|
||||||
|
|
||||||
# Get pages with limit
|
# Get pages with limit
|
||||||
result = await get_pages(limit=5)
|
result = await self.call_mcp_tool(mcp_server, "get_pages", limit=5)
|
||||||
response = json.loads(result)
|
response = json.loads(result)
|
||||||
|
|
||||||
assert "pages" in response
|
assert "pages" in response
|
||||||
|
|
@ -40,10 +37,10 @@ class TestPagesContentAPIE2E(BaseE2ETest):
|
||||||
|
|
||||||
async def test_get_pages_with_include_fields(self, mcp_server):
|
async def test_get_pages_with_include_fields(self, mcp_server):
|
||||||
"""Test getting pages with include fields."""
|
"""Test getting pages with include fields."""
|
||||||
from ghost_mcp.tools.content.pages import get_pages
|
|
||||||
|
|
||||||
# Get pages with tags and authors included
|
# Get pages with tags and authors included
|
||||||
result = await get_pages(include="tags,authors")
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "get_pages", include="tags,authors",
|
||||||
|
)
|
||||||
response = json.loads(result)
|
response = json.loads(result)
|
||||||
|
|
||||||
# Verify pages structure
|
# Verify pages structure
|
||||||
|
|
@ -55,55 +52,83 @@ class TestPagesContentAPIE2E(BaseE2ETest):
|
||||||
|
|
||||||
async def test_get_page_by_id(self, mcp_server, sample_page):
|
async def test_get_page_by_id(self, mcp_server, sample_page):
|
||||||
"""Test getting a page by ID."""
|
"""Test getting a page by ID."""
|
||||||
from ghost_mcp.tools.content.pages import get_page_by_id
|
# First, let's make sure the sample page is published so it's accessible via Content API
|
||||||
|
if sample_page.get("status") == "draft":
|
||||||
|
# If it's a draft, the Content API won't return it, which is expected
|
||||||
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "get_page_by_id", page_id=sample_page["id"],
|
||||||
|
)
|
||||||
|
response = json.loads(result)
|
||||||
|
# Should get an error for draft pages
|
||||||
|
assert "error" in response
|
||||||
|
assert ("not found" in response["error"].lower() or
|
||||||
|
"resource not found" in response["error"].lower())
|
||||||
|
else:
|
||||||
|
# Get published page by ID
|
||||||
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "get_page_by_id", page_id=sample_page["id"],
|
||||||
|
)
|
||||||
|
response = json.loads(result)
|
||||||
|
|
||||||
# Get page by ID
|
# Verify response
|
||||||
result = await get_page_by_id(sample_page["id"])
|
assert "pages" in response
|
||||||
response = json.loads(result)
|
assert len(response["pages"]) == 1
|
||||||
|
|
||||||
# Verify response
|
page = response["pages"][0]
|
||||||
assert "pages" in response
|
assert page["id"] == sample_page["id"]
|
||||||
assert len(response["pages"]) == 1
|
assert page["title"] == sample_page["title"]
|
||||||
|
|
||||||
page = response["pages"][0]
|
|
||||||
assert page["id"] == sample_page["id"]
|
|
||||||
assert page["title"] == sample_page["title"]
|
|
||||||
|
|
||||||
async def test_get_page_by_slug(self, mcp_server, sample_page):
|
async def test_get_page_by_slug(self, mcp_server, sample_page):
|
||||||
"""Test getting a page by slug."""
|
"""Test getting a page by slug."""
|
||||||
from ghost_mcp.tools.content.pages import get_page_by_slug
|
# First, let's make sure the sample page is published so it's accessible via Content API
|
||||||
|
if sample_page.get("status") == "draft":
|
||||||
|
# If it's a draft, the Content API won't return it, which is expected
|
||||||
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "get_page_by_slug", slug=sample_page["slug"],
|
||||||
|
)
|
||||||
|
response = json.loads(result)
|
||||||
|
# Should get an error for draft pages
|
||||||
|
assert "error" in response
|
||||||
|
assert ("not found" in response["error"].lower() or
|
||||||
|
"resource not found" in response["error"].lower())
|
||||||
|
else:
|
||||||
|
# Get published page by slug
|
||||||
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "get_page_by_slug", slug=sample_page["slug"],
|
||||||
|
)
|
||||||
|
response = json.loads(result)
|
||||||
|
|
||||||
# Get page by slug
|
# Verify response
|
||||||
result = await get_page_by_slug(sample_page["slug"])
|
assert "pages" in response
|
||||||
response = json.loads(result)
|
assert len(response["pages"]) == 1
|
||||||
|
|
||||||
# Verify response
|
page = response["pages"][0]
|
||||||
assert "pages" in response
|
assert page["slug"] == sample_page["slug"]
|
||||||
assert len(response["pages"]) == 1
|
assert page["title"] == sample_page["title"]
|
||||||
|
|
||||||
page = response["pages"][0]
|
|
||||||
assert page["slug"] == sample_page["slug"]
|
|
||||||
assert page["title"] == sample_page["title"]
|
|
||||||
|
|
||||||
async def test_get_page_by_nonexistent_id(self, mcp_server):
|
async def test_get_page_by_nonexistent_id(self, mcp_server):
|
||||||
"""Test getting a page with non-existent ID returns proper error."""
|
"""Test getting a page with non-existent ID returns proper error."""
|
||||||
from ghost_mcp.tools.content.pages import get_page_by_id
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "get_page_by_id", page_id="nonexistent-id",
|
||||||
|
)
|
||||||
|
|
||||||
with pytest.raises(Exception) as exc_info:
|
# MCP tools return JSON error responses instead of raising exceptions
|
||||||
await get_page_by_id("nonexistent-id")
|
response = json.loads(result)
|
||||||
|
assert "error" in response
|
||||||
# Verify we get an appropriate error
|
assert ("not found" in response["error"].lower() or
|
||||||
assert "404" in str(exc_info.value) or "not found" in str(exc_info.value).lower()
|
"validation error" in response["error"].lower())
|
||||||
|
|
||||||
async def test_get_page_by_nonexistent_slug(self, mcp_server):
|
async def test_get_page_by_nonexistent_slug(self, mcp_server):
|
||||||
"""Test getting a page with non-existent slug returns proper error."""
|
"""Test getting a page with non-existent slug returns proper error."""
|
||||||
from ghost_mcp.tools.content.pages import get_page_by_slug
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "get_page_by_slug", slug="nonexistent-slug",
|
||||||
|
)
|
||||||
|
|
||||||
with pytest.raises(Exception) as exc_info:
|
# MCP tools return JSON error responses instead of raising exceptions
|
||||||
await get_page_by_slug("nonexistent-slug")
|
response = json.loads(result)
|
||||||
|
assert "error" in response
|
||||||
# Verify we get an appropriate error
|
assert ("not found" in response["error"].lower() or
|
||||||
assert "404" in str(exc_info.value) or "not found" in str(exc_info.value).lower()
|
"validation error" in response["error"].lower())
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.e2e
|
@pytest.mark.e2e
|
||||||
|
|
@ -113,14 +138,13 @@ class TestPagesAdminAPIE2E(BaseE2ETest):
|
||||||
|
|
||||||
async def test_create_page_draft(self, mcp_server, test_page_data, cleanup_test_content):
|
async def test_create_page_draft(self, mcp_server, test_page_data, cleanup_test_content):
|
||||||
"""Test creating a draft page."""
|
"""Test creating a draft page."""
|
||||||
from ghost_mcp.tools.admin.pages import create_page
|
|
||||||
|
|
||||||
# Create page
|
# Create page
|
||||||
result = await create_page(
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "create_page",
|
||||||
title=test_page_data["title"],
|
title=test_page_data["title"],
|
||||||
content=test_page_data["content"],
|
content=test_page_data["content"],
|
||||||
content_format=test_page_data["content_format"],
|
content_format=test_page_data["content_format"],
|
||||||
status=test_page_data["status"]
|
status=test_page_data["status"],
|
||||||
)
|
)
|
||||||
response = json.loads(result)
|
response = json.loads(result)
|
||||||
|
|
||||||
|
|
@ -139,14 +163,13 @@ class TestPagesAdminAPIE2E(BaseE2ETest):
|
||||||
|
|
||||||
async def test_create_page_published(self, mcp_server, test_page_data, cleanup_test_content):
|
async def test_create_page_published(self, mcp_server, test_page_data, cleanup_test_content):
|
||||||
"""Test creating a published page."""
|
"""Test creating a published page."""
|
||||||
from ghost_mcp.tools.admin.pages import create_page
|
|
||||||
|
|
||||||
# Create published page
|
# Create published page
|
||||||
result = await create_page(
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "create_page",
|
||||||
title=test_page_data["title"],
|
title=test_page_data["title"],
|
||||||
content=test_page_data["content"],
|
content=test_page_data["content"],
|
||||||
content_format=test_page_data["content_format"],
|
content_format=test_page_data["content_format"],
|
||||||
status="published"
|
status="published",
|
||||||
)
|
)
|
||||||
response = json.loads(result)
|
response = json.loads(result)
|
||||||
|
|
||||||
|
|
@ -162,17 +185,16 @@ class TestPagesAdminAPIE2E(BaseE2ETest):
|
||||||
|
|
||||||
async def test_create_page_with_custom_slug(self, mcp_server, test_page_data, cleanup_test_content):
|
async def test_create_page_with_custom_slug(self, mcp_server, test_page_data, cleanup_test_content):
|
||||||
"""Test creating a page with custom slug."""
|
"""Test creating a page with custom slug."""
|
||||||
from ghost_mcp.tools.admin.pages import create_page
|
|
||||||
|
|
||||||
custom_slug = "custom-test-page-slug"
|
custom_slug = "custom-test-page-slug"
|
||||||
|
|
||||||
# Create page with custom slug
|
# Create page with custom slug
|
||||||
result = await create_page(
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "create_page",
|
||||||
title=test_page_data["title"],
|
title=test_page_data["title"],
|
||||||
content=test_page_data["content"],
|
content=test_page_data["content"],
|
||||||
content_format=test_page_data["content_format"],
|
content_format=test_page_data["content_format"],
|
||||||
status=test_page_data["status"],
|
status=test_page_data["status"],
|
||||||
slug=custom_slug
|
slug=custom_slug,
|
||||||
)
|
)
|
||||||
response = json.loads(result)
|
response = json.loads(result)
|
||||||
|
|
||||||
|
|
@ -185,8 +207,6 @@ class TestPagesAdminAPIE2E(BaseE2ETest):
|
||||||
|
|
||||||
async def test_create_page_with_special_characters(self, mcp_server, cleanup_test_content):
|
async def test_create_page_with_special_characters(self, mcp_server, cleanup_test_content):
|
||||||
"""Test creating a page with special characters in title and content."""
|
"""Test creating a page with special characters in title and content."""
|
||||||
from ghost_mcp.tools.admin.pages import create_page
|
|
||||||
|
|
||||||
# Title and content with special characters
|
# Title and content with special characters
|
||||||
special_title = "Test Page with Special Characters: éñ中文 📄"
|
special_title = "Test Page with Special Characters: éñ中文 📄"
|
||||||
special_content = json.dumps({
|
special_content = json.dumps({
|
||||||
|
|
@ -201,30 +221,31 @@ class TestPagesAdminAPIE2E(BaseE2ETest):
|
||||||
"style": "",
|
"style": "",
|
||||||
"text": "Page content with émojis 📖 and unicode: 中文字符",
|
"text": "Page content with émojis 📖 and unicode: 中文字符",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"version": 1
|
"version": 1,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"direction": "ltr",
|
"direction": "ltr",
|
||||||
"format": "",
|
"format": "",
|
||||||
"indent": 0,
|
"indent": 0,
|
||||||
"type": "paragraph",
|
"type": "paragraph",
|
||||||
"version": 1
|
"version": 1,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
"direction": "ltr",
|
"direction": "ltr",
|
||||||
"format": "",
|
"format": "",
|
||||||
"indent": 0,
|
"indent": 0,
|
||||||
"type": "root",
|
"type": "root",
|
||||||
"version": 1
|
"version": 1,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
# Create page with special characters
|
# Create page with special characters
|
||||||
result = await create_page(
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "create_page",
|
||||||
title=special_title,
|
title=special_title,
|
||||||
content=special_content,
|
content=special_content,
|
||||||
content_format="lexical",
|
content_format="lexical",
|
||||||
status="draft"
|
status="draft",
|
||||||
)
|
)
|
||||||
response = json.loads(result)
|
response = json.loads(result)
|
||||||
|
|
||||||
|
|
@ -237,10 +258,10 @@ class TestPagesAdminAPIE2E(BaseE2ETest):
|
||||||
|
|
||||||
async def test_create_page_minimal_data(self, mcp_server, cleanup_test_content):
|
async def test_create_page_minimal_data(self, mcp_server, cleanup_test_content):
|
||||||
"""Test creating a page with minimal required data."""
|
"""Test creating a page with minimal required data."""
|
||||||
from ghost_mcp.tools.admin.pages import create_page
|
|
||||||
|
|
||||||
# Create page with only title
|
# Create page with only title
|
||||||
result = await create_page(title="Minimal Test Page")
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "create_page", title="Minimal Test Page",
|
||||||
|
)
|
||||||
response = json.loads(result)
|
response = json.loads(result)
|
||||||
|
|
||||||
# Verify page was created with defaults
|
# Verify page was created with defaults
|
||||||
|
|
@ -254,12 +275,12 @@ class TestPagesAdminAPIE2E(BaseE2ETest):
|
||||||
|
|
||||||
async def test_page_slug_generation(self, mcp_server, cleanup_test_content):
|
async def test_page_slug_generation(self, mcp_server, cleanup_test_content):
|
||||||
"""Test that page slugs are generated correctly from titles."""
|
"""Test that page slugs are generated correctly from titles."""
|
||||||
from ghost_mcp.tools.admin.pages import create_page
|
|
||||||
|
|
||||||
test_title = "Test Page Title With Spaces And Special-Characters!"
|
test_title = "Test Page Title With Spaces And Special-Characters!"
|
||||||
|
|
||||||
# Create page and check slug generation
|
# Create page and check slug generation
|
||||||
result = await create_page(title=test_title)
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "create_page", title=test_title,
|
||||||
|
)
|
||||||
response = json.loads(result)
|
response = json.loads(result)
|
||||||
|
|
||||||
page = response["pages"][0]
|
page = response["pages"][0]
|
||||||
|
|
@ -275,13 +296,12 @@ class TestPagesAdminAPIE2E(BaseE2ETest):
|
||||||
|
|
||||||
async def test_create_page_empty_content(self, mcp_server, cleanup_test_content):
|
async def test_create_page_empty_content(self, mcp_server, cleanup_test_content):
|
||||||
"""Test creating a page with empty content."""
|
"""Test creating a page with empty content."""
|
||||||
from ghost_mcp.tools.admin.pages import create_page
|
|
||||||
|
|
||||||
# Create page with empty content
|
# Create page with empty content
|
||||||
result = await create_page(
|
result = await self.call_mcp_tool(
|
||||||
|
mcp_server, "create_page",
|
||||||
title="Empty Content Page",
|
title="Empty Content Page",
|
||||||
content="",
|
content="",
|
||||||
status="draft"
|
status="draft",
|
||||||
)
|
)
|
||||||
response = json.loads(result)
|
response = json.loads(result)
|
||||||
|
|
||||||
|
|
@ -293,14 +313,13 @@ class TestPagesAdminAPIE2E(BaseE2ETest):
|
||||||
# Track for cleanup
|
# Track for cleanup
|
||||||
cleanup_test_content["track_page"](page["id"])
|
cleanup_test_content["track_page"](page["id"])
|
||||||
|
|
||||||
async def test_pages_vs_posts_distinction(self, mcp_server, sample_page, sample_published_post):
|
async def test_pages_vs_posts_distinction(
|
||||||
|
self, mcp_server, sample_page, sample_published_post, # noqa: ARG002
|
||||||
|
):
|
||||||
"""Test that pages and posts are properly distinguished."""
|
"""Test that pages and posts are properly distinguished."""
|
||||||
from ghost_mcp.tools.content.pages import get_pages
|
# Get pages and posts via Content API (only returns published content)
|
||||||
from ghost_mcp.tools.content.posts import get_posts
|
pages_result = await self.call_mcp_tool(mcp_server, "get_pages")
|
||||||
|
posts_result = await self.call_mcp_tool(mcp_server, "get_posts")
|
||||||
# Get pages and posts
|
|
||||||
pages_result = await get_pages()
|
|
||||||
posts_result = await get_posts()
|
|
||||||
|
|
||||||
pages_response = json.loads(pages_result)
|
pages_response = json.loads(pages_result)
|
||||||
posts_response = json.loads(posts_result)
|
posts_response = json.loads(posts_result)
|
||||||
|
|
@ -309,10 +328,22 @@ class TestPagesAdminAPIE2E(BaseE2ETest):
|
||||||
page_ids = [page["id"] for page in pages_response["pages"]]
|
page_ids = [page["id"] for page in pages_response["pages"]]
|
||||||
post_ids = [post["id"] for post in posts_response["posts"]]
|
post_ids = [post["id"] for post in posts_response["posts"]]
|
||||||
|
|
||||||
# Verify our sample page is in pages, not posts
|
# The sample_page is a draft, so it won't appear in Content API results
|
||||||
assert sample_page["id"] in page_ids
|
# But we can still verify that posts and pages are distinct by checking:
|
||||||
assert sample_page["id"] not in post_ids
|
# 1. No overlap between page and post IDs
|
||||||
|
# 2. Our published post appears in posts, not pages
|
||||||
|
overlap = set(page_ids) & set(post_ids)
|
||||||
|
assert len(overlap) == 0, (
|
||||||
|
f"Found overlapping IDs between pages and posts: {overlap}"
|
||||||
|
)
|
||||||
|
|
||||||
# Verify our sample post is in posts, not pages
|
# Verify our sample published post is in posts, not pages
|
||||||
assert sample_published_post["id"] in post_ids
|
assert sample_published_post["id"] in post_ids
|
||||||
assert sample_published_post["id"] not in page_ids
|
assert sample_published_post["id"] not in page_ids
|
||||||
|
|
||||||
|
# If there are any published pages, verify they're only in pages
|
||||||
|
if page_ids:
|
||||||
|
for page_id in page_ids:
|
||||||
|
assert page_id not in post_ids, (
|
||||||
|
f"Page ID {page_id} found in posts list"
|
||||||
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue