"""Issue comments integration tests.
This module tests the issue comment operations using the real GitHub API.
"""
import pytest
from datetime import datetime, timedelta
from pygithub_mcp_server.operations.issues import (
create_issue,
update_issue,
add_issue_comment,
list_issue_comments,
update_issue_comment,
delete_issue_comment,
)
from pygithub_mcp_server.schemas.issues import (
CreateIssueParams,
UpdateIssueParams,
IssueCommentParams,
ListIssueCommentsParams,
UpdateIssueCommentParams,
DeleteIssueCommentParams,
)
@pytest.mark.integration
def test_add_issue_comment(test_owner, test_repo_name, unique_id, with_retry):
"""Test adding a comment to an issue."""
# Setup
owner = test_owner
repo = test_repo_name
title = f"Test Issue (Add Comment) {unique_id}"
# Create an issue
@with_retry
def create_test_issue():
return create_issue(CreateIssueParams(
owner=owner,
repo=repo,
title=title
))
issue = create_test_issue()
try:
# Add a comment
comment_body = f"Test comment at {datetime.now().isoformat()}"
@with_retry
def add_test_comment():
return add_issue_comment(IssueCommentParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
body=comment_body
))
comment = add_test_comment()
# Verify
assert comment["body"] == comment_body
assert "id" in comment
assert "user" in comment
assert "created_at" in comment
finally:
# Cleanup
try:
@with_retry
def close_issue():
return update_issue(UpdateIssueParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
state="closed"
))
close_issue()
except Exception as e:
print(f"Failed to close issue during cleanup: {e}")
@pytest.mark.integration
def test_list_issue_comments(test_owner, test_repo_name, unique_id, with_retry):
"""Test listing comments on an issue."""
# Setup
owner = test_owner
repo = test_repo_name
title = f"Test Issue (List Comments) {unique_id}"
# Create an issue
@with_retry
def create_test_issue():
return create_issue(CreateIssueParams(
owner=owner,
repo=repo,
title=title
))
issue = create_test_issue()
try:
# Add a comment
comment_body = f"Test comment for listing at {datetime.now().isoformat()}"
@with_retry
def add_test_comment():
return add_issue_comment(IssueCommentParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
body=comment_body
))
comment = add_test_comment()
# List comments
@with_retry
def list_test_comments():
return list_issue_comments(ListIssueCommentsParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"]
))
comments = list_test_comments()
# Verify
assert isinstance(comments, list)
assert len(comments) >= 1
# Verify our comment is in the list
found = False
for c in comments:
if c["id"] == comment["id"]:
found = True
assert c["body"] == comment_body
break
assert found, "Test comment not found in list_issue_comments results"
finally:
# Cleanup
try:
@with_retry
def close_issue():
return update_issue(UpdateIssueParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
state="closed"
))
close_issue()
except Exception as e:
print(f"Failed to close issue during cleanup: {e}")
@pytest.mark.integration
def test_update_issue_comment(test_owner, test_repo_name, unique_id, with_retry):
"""Test updating a comment on an issue."""
# Setup
owner = test_owner
repo = test_repo_name
title = f"Test Issue (Update Comment) {unique_id}"
# Create an issue
@with_retry
def create_test_issue():
return create_issue(CreateIssueParams(
owner=owner,
repo=repo,
title=title
))
issue = create_test_issue()
try:
# Add a comment
comment_body = f"Initial comment at {datetime.now().isoformat()}"
@with_retry
def add_test_comment():
return add_issue_comment(IssueCommentParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
body=comment_body
))
comment = add_test_comment()
# Update the comment
updated_body = f"Updated comment at {datetime.now().isoformat()}"
@with_retry
def update_test_comment():
return update_issue_comment(UpdateIssueCommentParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
comment_id=comment["id"],
body=updated_body
))
updated = update_test_comment()
# Verify
assert updated["id"] == comment["id"]
assert updated["body"] == updated_body
assert updated["body"] != comment_body
# List comments to verify update
@with_retry
def list_test_comments():
return list_issue_comments(ListIssueCommentsParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"]
))
comments = list_test_comments()
# Verify our updated comment is in the list
found = False
for c in comments:
if c["id"] == comment["id"]:
found = True
assert c["body"] == updated_body
break
assert found, "Updated comment not found in list_issue_comments results"
finally:
# Cleanup
try:
@with_retry
def close_issue():
return update_issue(UpdateIssueParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
state="closed"
))
close_issue()
except Exception as e:
print(f"Failed to close issue during cleanup: {e}")
@pytest.mark.integration
def test_delete_issue_comment(test_owner, test_repo_name, unique_id, with_retry):
"""Test deleting a comment from an issue."""
# Setup
owner = test_owner
repo = test_repo_name
title = f"Test Issue (Delete Comment) {unique_id}"
# Create an issue
@with_retry
def create_test_issue():
return create_issue(CreateIssueParams(
owner=owner,
repo=repo,
title=title
))
issue = create_test_issue()
try:
# Add a comment
comment_body = f"Comment to delete at {datetime.now().isoformat()}"
@with_retry
def add_test_comment():
return add_issue_comment(IssueCommentParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
body=comment_body
))
comment = add_test_comment()
# Verify comment exists
@with_retry
def list_test_comments_before():
return list_issue_comments(ListIssueCommentsParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"]
))
comments_before = list_test_comments_before()
found_before = False
for c in comments_before:
if c["id"] == comment["id"]:
found_before = True
break
assert found_before, "Comment not found before deletion"
# Delete the comment
@with_retry
def delete_test_comment():
return delete_issue_comment(DeleteIssueCommentParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
comment_id=comment["id"]
))
delete_test_comment()
# Verify comment is deleted
@with_retry
def list_test_comments_after():
return list_issue_comments(ListIssueCommentsParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"]
))
comments_after = list_test_comments_after()
for c in comments_after:
assert c["id"] != comment["id"], "Comment still exists after deletion"
finally:
# Cleanup
try:
@with_retry
def close_issue():
return update_issue(UpdateIssueParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
state="closed"
))
close_issue()
except Exception as e:
print(f"Failed to close issue during cleanup: {e}")
@pytest.mark.integration
def test_list_issue_comments_since(test_owner, test_repo_name, unique_id, with_retry):
"""Test listing comments on an issue with since parameter."""
# Setup
owner = test_owner
repo = test_repo_name
title = f"Test Issue (List Comments Since) {unique_id}"
# Create an issue
@with_retry
def create_test_issue():
return create_issue(CreateIssueParams(
owner=owner,
repo=repo,
title=title
))
issue = create_test_issue()
try:
# Add a comment
comment_body = f"Test comment for since filter at {datetime.now().isoformat()}"
@with_retry
def add_test_comment():
return add_issue_comment(IssueCommentParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
body=comment_body
))
comment = add_test_comment()
# Get the current time
now = datetime.now()
# Set since to 1 hour ago
since = now - timedelta(hours=1)
# List comments since 1 hour ago
@with_retry
def list_test_comments_since():
return list_issue_comments(ListIssueCommentsParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
since=since.isoformat() + "Z" # Add UTC timezone indicator
))
recent_comments = list_test_comments_since()
# Verify our comment is in the list
found = False
for c in recent_comments:
if c["id"] == comment["id"]:
found = True
assert c["body"] == comment_body
break
assert found, "Test comment not found in since filter results"
# Set since to 24 hours in the future to ensure timezone differences are covered
future = now + timedelta(hours=24)
# List comments since 1 hour in the future
@with_retry
def list_test_comments_future():
return list_issue_comments(ListIssueCommentsParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
since=future.isoformat() + "Z" # Add UTC timezone indicator
))
future_comments = list_test_comments_future()
# Verify our comment is not in the list
for c in future_comments:
assert c["id"] != comment["id"], "Comment found with future since filter"
finally:
# Cleanup
try:
@with_retry
def close_issue():
return update_issue(UpdateIssueParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
state="closed"
))
close_issue()
except Exception as e:
print(f"Failed to close issue during cleanup: {e}")
@pytest.mark.integration
def test_comment_lifecycle(test_owner, test_repo_name, unique_id, with_retry):
"""Test complete comment lifecycle (add → list → update → delete)."""
# Setup
owner = test_owner
repo = test_repo_name
title = f"Test Issue (Comment Lifecycle) {unique_id}"
# Create an issue
@with_retry
def create_test_issue():
return create_issue(CreateIssueParams(
owner=owner,
repo=repo,
title=title
))
issue = create_test_issue()
try:
# Add a comment
comment_body = f"Initial comment at {datetime.now().isoformat()}"
@with_retry
def add_test_comment():
return add_issue_comment(IssueCommentParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
body=comment_body
))
comment = add_test_comment()
assert comment["body"] == comment_body
# List comments
@with_retry
def list_test_comments():
return list_issue_comments(ListIssueCommentsParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"]
))
comments = list_test_comments()
found = False
for c in comments:
if c["id"] == comment["id"]:
found = True
break
assert found, "Comment not found in list after adding"
# Update comment
updated_body = f"Updated comment at {datetime.now().isoformat()}"
@with_retry
def update_test_comment():
return update_issue_comment(UpdateIssueCommentParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
comment_id=comment["id"],
body=updated_body
))
updated = update_test_comment()
assert updated["body"] == updated_body
# List comments again to verify update
@with_retry
def list_test_comments_after_update():
return list_issue_comments(ListIssueCommentsParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"]
))
comments_after_update = list_test_comments_after_update()
found_updated = False
for c in comments_after_update:
if c["id"] == comment["id"]:
found_updated = True
assert c["body"] == updated_body
break
assert found_updated, "Updated comment not found in list"
# Delete comment
@with_retry
def delete_test_comment():
return delete_issue_comment(DeleteIssueCommentParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
comment_id=comment["id"]
))
delete_test_comment()
# List comments again to verify deletion
@with_retry
def list_test_comments_after_delete():
return list_issue_comments(ListIssueCommentsParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"]
))
comments_after_delete = list_test_comments_after_delete()
for c in comments_after_delete:
assert c["id"] != comment["id"], "Comment still exists after deletion"
finally:
# Cleanup
try:
@with_retry
def close_issue():
return update_issue(UpdateIssueParams(
owner=owner,
repo=repo,
issue_number=issue["issue_number"],
state="closed"
))
close_issue()
except Exception as e:
print(f"Failed to close issue during cleanup: {e}")