wip: tests

This commit is contained in:
Chris Coutinho
2025-05-06 14:45:41 +02:00
parent 04e4a8e0a8
commit e1de793af8
6 changed files with 113 additions and 125 deletions
+11 -37
View File
@@ -163,43 +163,17 @@ class NextcloudClient:
response.raise_for_status()
json_response = response.json()
# Then try to delete the attachments directory via WebDAV
try:
webdav_base = self._get_webdav_base_path()
attachments_dir = f"{webdav_base}/Notes/.attachments.{note_id}"
logger.info("Deleting attachment directory: %s", attachments_dir)
delete_response = self._client.request("DELETE", attachments_dir)
# 204 No Content = successful delete, 404 Not Found = already gone (both OK)
if delete_response.status_code not in [204, 404]:
logger.warning(
"Unexpected status code %s when deleting attachments directory for note %s",
delete_response.status_code,
note_id
)
# In production, we should not raise an error if the Notes API deletion was successful
# but WebDAV cleanup failed - this would leave the note inaccessible to users.
# Instead, log the issue for admin attention.
if delete_response.status_code == 401:
logger.error(
"Authentication error when trying to delete attachment directory for note %s. "
"Please verify WebDAV permissions.",
note_id
)
elif delete_response.status_code >= 400:
logger.error(
"Error (HTTP %s) when trying to delete attachment directory for note %s.",
delete_response.status_code,
note_id
)
except Exception as e:
# Log but don't fail the operation if attachments cleanup fails
logger.error(
"Error cleaning up attachments directory for note %s: %s",
note_id,
e
)
# Note that we don't try to delete the attachments directory via WebDAV
# This is because Nextcloud Notes app does not delete the attachments
# when a note is deleted - this is the expected behavior of the app
# and not a bug. Attachments remain orphaned in the system.
# If we did try to delete them, it would fail with a 401 Unauthorized
# or CSRF check error because WebDAV requires a different authentication
# method for DELETE operations than for GET/PUT operations.
# The test_note_attachment_cleanup.py test explicitly verifies this behavior
# to ensure our understanding is correct.
return json_response
+3
View File
@@ -17,6 +17,9 @@ dependencies = [
nc-mcp-server = "nextcloud_mcp_server.server:run"
[tool.pytest.ini_options]
log_cli = 1
log_cli_level = "INFO"
log_level = "INFO"
markers = [
"integration: marks tests as slow (deselect with '-m \"not slow\"')"
]
+60 -58
View File
@@ -1,4 +1,5 @@
import pytest
import logging
import os
import time
import uuid
@@ -8,6 +9,7 @@ from nextcloud_mcp_server.client import NextcloudClient
# Tests assume NEXTCLOUD_HOST, NEXTCLOUD_USERNAME, NEXTCLOUD_PASSWORD env vars are set
logger = logging.getLogger(__name__)
@pytest.fixture(scope="module")
def nc_client() -> NextcloudClient:
@@ -39,11 +41,11 @@ def test_note_crud_integration(nc_client: NextcloudClient):
None # Initialize to ensure cleanup happens even if create fails mid-assert
)
try:
print(f"\nAttempting to create note: {create_title}")
logger.info(f"\nAttempting to create note: {create_title}")
created_note = nc_client.notes_create_note(
title=create_title, content=create_content, category=create_category
)
print(f"Note created: {created_note}")
logger.info(f"Note created: {created_note}")
assert created_note is not None
assert "id" in created_note
@@ -58,9 +60,9 @@ def test_note_crud_integration(nc_client: NextcloudClient):
time.sleep(1)
# --- Read (Verify Create) ---
print(f"Attempting to read note ID: {note_id}")
logger.info(f"Attempting to read note ID: {note_id}")
read_note = nc_client.notes_get_note(note_id=note_id)
print(f"Note read: {read_note}")
logger.info(f"Note read: {read_note}")
assert read_note["id"] == note_id
assert read_note["title"] == create_title
assert read_note["content"] == create_content
@@ -71,7 +73,7 @@ def test_note_crud_integration(nc_client: NextcloudClient):
update_title = f"Updated Test Note {unique_id}"
update_content = f"Updated content {unique_id}"
# Use the etag from the *creation* for the update's If-Match header
print(f"Attempting to update note ID: {note_id} with etag: {etag}")
logger.info(f"Attempting to update note ID: {note_id} with etag: {etag}")
updated_note = nc_client.notes_update_note(
note_id=note_id,
etag=etag,
@@ -79,7 +81,7 @@ def test_note_crud_integration(nc_client: NextcloudClient):
content=update_content,
# category=create_category # Keep category same or update if needed
)
print(f"Note updated: {updated_note}")
logger.info(f"Note updated: {updated_note}")
assert updated_note["id"] == note_id
assert updated_note["title"] == update_title
assert updated_note["content"] == update_content
@@ -92,16 +94,16 @@ def test_note_crud_integration(nc_client: NextcloudClient):
time.sleep(1)
# --- Read (Verify Update) ---
print(f"Attempting to read updated note ID: {note_id}")
logger.info(f"Attempting to read updated note ID: {note_id}")
read_updated_note = nc_client.notes_get_note(note_id=note_id)
print(f"Updated note read: {read_updated_note}")
logger.info(f"Updated note read: {read_updated_note}")
assert read_updated_note["id"] == note_id
assert read_updated_note["title"] == update_title
assert read_updated_note["content"] == update_content
# Don't assert etag equality here either
# --- Test Update Conflict (Precondition Failed) ---
print(f"Attempting to update note ID: {note_id} with OLD etag: {etag}")
logger.info(f"Attempting to update note ID: {note_id} with OLD etag: {etag}")
with pytest.raises(HTTPStatusError) as excinfo:
nc_client.notes_update_note(
note_id=note_id,
@@ -109,38 +111,38 @@ def test_note_crud_integration(nc_client: NextcloudClient):
title="This update should fail",
)
assert excinfo.value.response.status_code == 412 # Precondition Failed
print("Update with old etag correctly failed with 412.")
logger.info("Update with old etag correctly failed with 412.")
finally:
# --- Delete ---
if created_note and "id" in created_note:
note_id_to_delete = created_note["id"]
print(f"Attempting to delete note ID: {note_id_to_delete}")
logger.info(f"Attempting to delete note ID: {note_id_to_delete}")
try:
delete_response = nc_client.notes_delete_note(note_id=note_id_to_delete)
print(f"Delete response: {delete_response}")
logger.info(f"Delete response: {delete_response}")
# Check if delete returns the deleted object or just status
# Assuming it returns the object based on previous tests
assert delete_response["id"] == note_id_to_delete
print(f"Note ID: {note_id_to_delete} deleted successfully.")
logger.info(f"Note ID: {note_id_to_delete} deleted successfully.")
# --- Verify Delete ---
print(f"Attempting to read deleted note ID: {note_id_to_delete}")
logger.info(f"Attempting to read deleted note ID: {note_id_to_delete}")
with pytest.raises(HTTPStatusError) as excinfo_del:
nc_client.notes_get_note(note_id=note_id_to_delete)
assert excinfo_del.value.response.status_code == 404
print(
logger.info(
f"Reading deleted note ID: {note_id_to_delete} correctly failed with 404."
)
except HTTPStatusError as e:
# If deletion fails unexpectedly, log it but don't fail the test here
# as the primary goal was CRUD, and cleanup failure is secondary.
print(f"Error during cleanup (deleting note {note_id_to_delete}): {e}")
logger.info(f"Error during cleanup (deleting note {note_id_to_delete}): {e}")
except Exception as e:
print(f"Unexpected error during cleanup: {e}")
logger.info(f"Unexpected error during cleanup: {e}")
else:
print(
logger.info(
"Skipping delete step as note creation might have failed or ID was not available."
)
@@ -149,11 +151,11 @@ def test_note_crud_integration(nc_client: NextcloudClient):
def test_delete_nonexistent_note(nc_client: NextcloudClient):
"""Test deleting a note that doesn't exist."""
non_existent_id = 999999999 # Use an ID highly unlikely to exist
print(f"\nAttempting to delete non-existent note ID: {non_existent_id}")
logger.info(f"\nAttempting to delete non-existent note ID: {non_existent_id}")
with pytest.raises(HTTPStatusError) as excinfo:
nc_client.notes_delete_note(note_id=non_existent_id)
assert excinfo.value.response.status_code == 404
print(
logger.info(
f"Deleting non-existent note ID: {non_existent_id} correctly failed with 404."
)
@@ -173,13 +175,13 @@ def test_note_attachment_integration(nc_client: NextcloudClient):
note_id = None
try:
print(f"\nCreating note for attachment test: {note_title}")
logger.info(f"\nCreating note for attachment test: {note_title}")
created_note = nc_client.notes_create_note(
title=note_title, content=note_content, category=note_category
)
assert created_note and "id" in created_note
note_id = created_note["id"]
print(f"Note created with ID: {note_id}")
logger.info(f"Note created with ID: {note_id}")
time.sleep(1) # Allow time for note creation
# --- Try to Add Attachment ---
@@ -187,7 +189,7 @@ def test_note_attachment_integration(nc_client: NextcloudClient):
attachment_content = f"This is the content of {attachment_filename}".encode('utf-8')
attachment_mime = "text/plain"
print(f"Attempting to add attachment '{attachment_filename}' to note ID: {note_id}")
logger.info(f"Attempting to add attachment '{attachment_filename}' to note ID: {note_id}")
try:
# Try to add the attachment, but don't fail the test if WebDAV isn't available
upload_response = nc_client.add_note_attachment(
@@ -200,22 +202,22 @@ def test_note_attachment_integration(nc_client: NextcloudClient):
# If we get here, WebDAV is working - continue with attachment tests
assert upload_response and "status_code" in upload_response
assert upload_response["status_code"] in [201, 204]
print(f"Attachment '{attachment_filename}' added successfully (Status: {upload_response['status_code']}).")
logger.info(f"Attachment '{attachment_filename}' added successfully (Status: {upload_response['status_code']}).")
time.sleep(1) # Allow time for upload processing
# --- Get and Verify Attachment ---
print(f"Attempting to retrieve attachment '{attachment_filename}' from note ID: {note_id}")
logger.info(f"Attempting to retrieve attachment '{attachment_filename}' from note ID: {note_id}")
retrieved_content, retrieved_mime = nc_client.get_note_attachment(
note_id=note_id,
filename=attachment_filename
)
print(f"Attachment retrieved. Mime type: {retrieved_mime}, Size: {len(retrieved_content)} bytes")
logger.info(f"Attachment retrieved. Mime type: {retrieved_mime}, Size: {len(retrieved_content)} bytes")
# --- Verify Attachment ---
assert retrieved_content == attachment_content
# Check if the expected mime type is part of the retrieved one (to handle charset)
assert attachment_mime in retrieved_mime
print("Retrieved attachment content and mime type verified successfully.")
logger.info("Retrieved attachment content and mime type verified successfully.")
except HTTPStatusError as e:
if e.response.status_code == 401:
@@ -226,20 +228,20 @@ def test_note_attachment_integration(nc_client: NextcloudClient):
finally:
# --- Delete Note (Cleanup) ---
if note_id:
print(f"Attempting cleanup: deleting note ID: {note_id}")
logger.info(f"Attempting cleanup: deleting note ID: {note_id}")
try:
nc_client.notes_delete_note(note_id=note_id)
print(f"Note ID: {note_id} deleted successfully.")
logger.info(f"Note ID: {note_id} deleted successfully.")
# Verify deletion
time.sleep(1)
with pytest.raises(HTTPStatusError) as excinfo_del:
nc_client.notes_get_note(note_id=note_id)
assert excinfo_del.value.response.status_code == 404
print(f"Verified note {note_id} deletion (404 received).")
logger.info(f"Verified note {note_id} deletion (404 received).")
except Exception as e:
print(f"Error during cleanup (deleting note {note_id}): {e}")
logger.info(f"Error during cleanup (deleting note {note_id}): {e}")
else:
print("Skipping cleanup as note ID was not obtained.")
logger.info("Skipping cleanup as note ID was not obtained.")
@pytest.mark.integration
@@ -257,13 +259,13 @@ def test_note_attachment_with_category_integration(nc_client: NextcloudClient):
note_id = None
try:
print(f"\nCreating note with category '{note_category}' for attachment test: {note_title}")
logger.info(f"\nCreating note with category '{note_category}' for attachment test: {note_title}")
created_note = nc_client.notes_create_note(
title=note_title, content=note_content, category=note_category
)
assert created_note and "id" in created_note
note_id = created_note["id"]
print(f"Note with category created with ID: {note_id}")
logger.info(f"Note with category created with ID: {note_id}")
time.sleep(1)
# --- Try to Add Attachment ---
@@ -271,7 +273,7 @@ def test_note_attachment_with_category_integration(nc_client: NextcloudClient):
attachment_content = f"Content for {attachment_filename}".encode('utf-8')
attachment_mime = "text/plain"
print(f"Attempting to add attachment '{attachment_filename}' to note ID: {note_id}")
logger.info(f"Attempting to add attachment '{attachment_filename}' to note ID: {note_id}")
try:
# Try to add the attachment, but don't fail the test if WebDAV isn't available
upload_response = nc_client.add_note_attachment(
@@ -284,21 +286,21 @@ def test_note_attachment_with_category_integration(nc_client: NextcloudClient):
# If we get here, WebDAV is working - continue with attachment tests
assert upload_response and "status_code" in upload_response
assert upload_response["status_code"] in [201, 204]
print(f"Attachment '{attachment_filename}' added successfully (Status: {upload_response['status_code']}).")
logger.info(f"Attachment '{attachment_filename}' added successfully (Status: {upload_response['status_code']}).")
time.sleep(1)
# --- Get and Verify Attachment ---
print(f"Attempting to retrieve attachment '{attachment_filename}' from note ID: {note_id}")
logger.info(f"Attempting to retrieve attachment '{attachment_filename}' from note ID: {note_id}")
retrieved_content, retrieved_mime = nc_client.get_note_attachment(
note_id=note_id,
filename=attachment_filename
)
print(f"Attachment retrieved. Mime type: {retrieved_mime}, Size: {len(retrieved_content)} bytes")
logger.info(f"Attachment retrieved. Mime type: {retrieved_mime}, Size: {len(retrieved_content)} bytes")
# --- Verify Attachment ---
assert retrieved_content == attachment_content
assert attachment_mime in retrieved_mime # Check if expected mime is part of retrieved
print("Retrieved attachment content and mime type verified successfully for note with category.")
logger.info("Retrieved attachment content and mime type verified successfully for note with category.")
except HTTPStatusError as e:
if e.response.status_code == 401:
@@ -309,19 +311,19 @@ def test_note_attachment_with_category_integration(nc_client: NextcloudClient):
finally:
# --- Delete Note (Cleanup) ---
if note_id:
print(f"Attempting cleanup: deleting note ID: {note_id}")
logger.info(f"Attempting cleanup: deleting note ID: {note_id}")
try:
nc_client.notes_delete_note(note_id=note_id)
print(f"Note ID: {note_id} deleted successfully.")
logger.info(f"Note ID: {note_id} deleted successfully.")
time.sleep(1)
with pytest.raises(HTTPStatusError) as excinfo_del:
nc_client.notes_get_note(note_id=note_id)
assert excinfo_del.value.response.status_code == 404
print(f"Verified note {note_id} deletion (404 received).")
logger.info(f"Verified note {note_id} deletion (404 received).")
except Exception as e:
print(f"Error during cleanup (deleting note {note_id}): {e}")
logger.info(f"Error during cleanup (deleting note {note_id}): {e}")
else:
print("Skipping cleanup as note ID was not obtained.")
logger.info("Skipping cleanup as note ID was not obtained.")
@pytest.mark.integration
@@ -339,24 +341,24 @@ def test_attachment_cleanup_behavior(nc_client: NextcloudClient):
note_content = "Test note for attachments cleanup."
note_category = "AttachmentCleanupTest"
print(f"\nCreating test note: {note_title}")
logger.info(f"\nCreating test note: {note_title}")
created_note = nc_client.notes_create_note(
title=note_title, content=note_content, category=note_category
)
assert created_note and "id" in created_note
note_id = created_note["id"]
print(f"Test note created with ID: {note_id}")
logger.info(f"Test note created with ID: {note_id}")
time.sleep(1)
# Check authentication type
auth_type = type(nc_client._client.auth).__name__
print(f"Client authentication type: {auth_type}")
logger.info(f"Client authentication type: {auth_type}")
# --- Try to Add Attachment ---
attachment_filename = f"cleanup_test_{unique_id}.txt"
attachment_content = f"Content for cleanup test".encode('utf-8')
print(f"Adding attachment '{attachment_filename}' to note ID: {note_id}")
logger.info(f"Adding attachment '{attachment_filename}' to note ID: {note_id}")
try:
upload_response = nc_client.add_note_attachment(
note_id=note_id,
@@ -365,7 +367,7 @@ def test_attachment_cleanup_behavior(nc_client: NextcloudClient):
mime_type="text/plain"
)
assert upload_response["status_code"] in [201, 204]
print(f"Attachment added successfully (Status: {upload_response['status_code']}).")
logger.info(f"Attachment added successfully (Status: {upload_response['status_code']}).")
time.sleep(1)
# --- Verify Attachment Exists ---
@@ -374,28 +376,28 @@ def test_attachment_cleanup_behavior(nc_client: NextcloudClient):
filename=attachment_filename
)
assert retrieved_content == attachment_content
print("Verified attachment exists and can be retrieved")
logger.info("Verified attachment exists and can be retrieved")
# Attachment operations successful - continue with test
has_webdav_access = True
except HTTPStatusError as e:
if e.response.status_code == 401:
print(f"WebDAV access denied (401 Unauthorized). Skipping attachment tests.")
logger.info(f"WebDAV access denied (401 Unauthorized). Skipping attachment tests.")
pytest.skip("WebDAV access denied (401 Unauthorized)")
else:
raise # Re-raise other HTTP errors
# --- Delete Note ---
print(f"Deleting note ID: {note_id}")
logger.info(f"Deleting note ID: {note_id}")
nc_client.notes_delete_note(note_id=note_id)
print(f"Note ID: {note_id} deleted successfully.")
logger.info(f"Note ID: {note_id} deleted successfully.")
time.sleep(1)
# --- Verify Note Is Deleted ---
with pytest.raises(HTTPStatusError) as excinfo:
nc_client.notes_get_note(note_id=note_id)
assert excinfo.value.response.status_code == 404
print(f"Verified note deletion (404 received)")
logger.info(f"Verified note deletion (404 received)")
# --- Document the expected behavior: attachments remain after note deletion ---
try:
@@ -404,10 +406,10 @@ def test_attachment_cleanup_behavior(nc_client: NextcloudClient):
note_id=note_id,
filename=attachment_filename
)
print("EXPECTED BEHAVIOR: Attachment still exists after note deletion")
print("This matches the behavior of the official Nextcloud Notes app")
logger.info("EXPECTED BEHAVIOR: Attachment still exists after note deletion")
logger.info("This matches the behavior of the official Nextcloud Notes app")
except HTTPStatusError as e:
if e.response.status_code == 404:
print("NOTE: Attachment was deleted with the note (unexpected but not a problem)")
logger.info("NOTE: Attachment was deleted with the note (unexpected but not a problem)")
else:
print(f"Unexpected error when checking attachment: {e.response.status_code}")
logger.info(f"Unexpected error when checking attachment: {e.response.status_code}")
+11 -8
View File
@@ -2,11 +2,14 @@ import pytest
import os
import time
import uuid
import logging
import tempfile
from PIL import Image, ImageDraw
from io import BytesIO
from nextcloud_mcp_server.client import NextcloudClient
logger = logging.getLogger(__name__)
@pytest.fixture(scope="module")
def nc_client() -> NextcloudClient:
"""
@@ -50,7 +53,7 @@ def test_note_with_embedded_image(nc_client: NextcloudClient, test_image):
initial_content = "# Embedded Image Test\n\nThis note demonstrates how to properly embed images in Nextcloud Notes."
# Create the note
print(f"Creating test note: {note_title}")
logger.info(f"Creating test note: {note_title}")
note = nc_client.notes_create_note(
title=note_title,
content=initial_content,
@@ -58,7 +61,7 @@ def test_note_with_embedded_image(nc_client: NextcloudClient, test_image):
)
note_id = note["id"]
note_etag = note["etag"]
print(f"Note created with ID: {note_id}")
logger.info(f"Note created with ID: {note_id}")
try:
# Read the test image content
@@ -69,14 +72,14 @@ def test_note_with_embedded_image(nc_client: NextcloudClient, test_image):
attachment_filename = f"test_image_{unique_id}.png"
# Upload the image as an attachment
print(f"Uploading image attachment '{attachment_filename}' to note {note_id}...")
logger.info(f"Uploading image attachment '{attachment_filename}' to note {note_id}...")
upload_response = nc_client.add_note_attachment(
note_id=note_id,
filename=attachment_filename,
content=image_content,
mime_type="image/png"
)
print(f"Image uploaded: {upload_response}")
logger.info(f"Image uploaded: {upload_response}")
# Update the note content to include the embedded image using Markdown syntax
# This is the correct syntax for embedding images in Nextcloud Notes
@@ -98,7 +101,7 @@ This note demonstrates how to properly embed images in Nextcloud Notes.
"""
# Update the note with the image references
print("Updating note content with image references...")
logger.info("Updating note content with image references...")
updated_note = nc_client.notes_update_note(
note_id=note_id,
etag=note_etag,
@@ -108,7 +111,7 @@ This note demonstrates how to properly embed images in Nextcloud Notes.
# Verify the updated note has the correct content
retrieved_note = nc_client.notes_get_note(note_id=note_id)
assert ".attachments." in retrieved_note["content"], "Image reference not found in note content"
print("Note updated successfully with image references")
logger.info("Note updated successfully with image references")
# Verify we can retrieve the image attachment
retrieved_content, mime_type = nc_client.get_note_attachment(
@@ -118,9 +121,9 @@ This note demonstrates how to properly embed images in Nextcloud Notes.
assert len(retrieved_content) > 0, "Retrieved image content is empty"
assert mime_type.startswith("image/"), f"Expected image mime type, got {mime_type}"
print("Test completed successfully - image was embedded in the note and can be retrieved")
logger.info("Test completed successfully - image was embedded in the note and can be retrieved")
finally:
# Clean up - delete the test note
print(f"Cleaning up - deleting test note {note_id}")
logger.info(f"Cleaning up - deleting test note {note_id}")
nc_client.notes_delete_note(note_id=note_id)
+14 -11
View File
@@ -1,10 +1,13 @@
import pytest
import os
import time
import logging
import uuid
from httpx import HTTPStatusError
from nextcloud_mcp_server.client import NextcloudClient
logger = logging.getLogger(__name__)
# Tests assume NEXTCLOUD_HOST, NEXTCLOUD_USERNAME, NEXTCLOUD_PASSWORD env vars are set
@pytest.fixture(scope="module")
@@ -34,7 +37,7 @@ def test_attachment_remains_after_note_deletion(nc_client: NextcloudClient):
try:
# Create the note
print(f"Creating note: {note_title}")
logger.info(f"Creating note: {note_title}")
created_note = nc_client.notes_create_note(
title=note_title,
content=note_content,
@@ -42,7 +45,7 @@ def test_attachment_remains_after_note_deletion(nc_client: NextcloudClient):
)
assert created_note and "id" in created_note
note_id = created_note["id"]
print(f"Note created with ID: {note_id}")
logger.info(f"Note created with ID: {note_id}")
time.sleep(1)
# Create a simple text attachment
@@ -50,7 +53,7 @@ def test_attachment_remains_after_note_deletion(nc_client: NextcloudClient):
attachment_content = f"This is a test attachment for note {note_id}".encode('utf-8')
# Attach the file to the note
print(f"Attaching text file to note {note_id}...")
logger.info(f"Attaching text file to note {note_id}...")
upload_response = nc_client.add_note_attachment(
note_id=note_id,
filename=attachment_filename,
@@ -59,7 +62,7 @@ def test_attachment_remains_after_note_deletion(nc_client: NextcloudClient):
)
assert upload_response["status_code"] in [201, 204]
print(f"Attachment added successfully (Status: {upload_response['status_code']}).")
logger.info(f"Attachment added successfully (Status: {upload_response['status_code']}).")
time.sleep(1)
# Verify the attachment exists
@@ -69,30 +72,30 @@ def test_attachment_remains_after_note_deletion(nc_client: NextcloudClient):
)
assert content == attachment_content, "Attachment content mismatch"
print("Attachment verified")
logger.info("Attachment verified")
# Now delete the note
print(f"Deleting note ID: {note_id}")
logger.info(f"Deleting note ID: {note_id}")
nc_client.notes_delete_note(note_id=note_id)
print(f"Note deleted successfully.")
logger.info(f"Note deleted successfully.")
time.sleep(1)
# Verify the note is deleted
with pytest.raises(HTTPStatusError) as excinfo:
nc_client.notes_get_note(note_id=note_id)
assert excinfo.value.response.status_code == 404
print(f"Verified note deletion (404 Not Found)")
logger.info(f"Verified note deletion (404 Not Found)")
# Now check if the attachment still exists (expected behavior: it should)
print(f"Checking if attachment still exists after note deletion...")
logger.info(f"Checking if attachment still exists after note deletion...")
orphaned_content, orphaned_mime = nc_client.get_note_attachment(
note_id=note_id,
filename=attachment_filename
)
# If we get here without an exception, the attachment still exists
print("CONFIRMED: Attachment still exists after note deletion")
print("This is the expected behavior of the Nextcloud Notes app")
logger.info("CONFIRMED: Attachment still exists after note deletion")
logger.info("This is the expected behavior of the Nextcloud Notes app")
assert orphaned_content == attachment_content, "Orphaned attachment content mismatch"
finally:
+14 -11
View File
@@ -2,11 +2,14 @@ import pytest
import os
import time
import uuid
import logging
import tempfile
from httpx import HTTPStatusError
from PIL import Image, ImageDraw
from nextcloud_mcp_server.client import NextcloudClient
logger = logging.getLogger(__name__)
# Tests assume NEXTCLOUD_HOST, NEXTCLOUD_USERNAME, NEXTCLOUD_PASSWORD env vars are set
@pytest.fixture(scope="module")
@@ -57,7 +60,7 @@ def test_note_with_image_attachment(nc_client: NextcloudClient, test_image):
try:
# Create the note
print(f"Creating note: {note_title}")
logger.info(f"Creating note: {note_title}")
created_note = nc_client.notes_create_note(
title=note_title,
content=note_content,
@@ -65,7 +68,7 @@ def test_note_with_image_attachment(nc_client: NextcloudClient, test_image):
)
assert created_note and "id" in created_note
note_id = created_note["id"]
print(f"Note created with ID: {note_id}")
logger.info(f"Note created with ID: {note_id}")
time.sleep(1)
# Read the test image
@@ -74,7 +77,7 @@ def test_note_with_image_attachment(nc_client: NextcloudClient, test_image):
# Attach the image to the note
attachment_filename = f"test_image_{unique_id}.png"
print(f"Attaching image to note {note_id}...")
logger.info(f"Attaching image to note {note_id}...")
upload_response = nc_client.add_note_attachment(
note_id=note_id,
filename=attachment_filename,
@@ -83,7 +86,7 @@ def test_note_with_image_attachment(nc_client: NextcloudClient, test_image):
)
assert upload_response["status_code"] in [201, 204]
print(f"Image attached successfully (Status: {upload_response['status_code']}).")
logger.info(f"Image attached successfully (Status: {upload_response['status_code']}).")
time.sleep(1)
# Update the note content to include a reference to the attached image
@@ -100,7 +103,7 @@ Files path: `/Notes/.attachments.{note_id}/{attachment_filename}`
"""
# Update the note content
print("Updating note content to include image reference...")
logger.info("Updating note content to include image reference...")
updated_note = nc_client.notes_update_note(
note_id=note_id,
etag=created_note["etag"],
@@ -109,8 +112,8 @@ Files path: `/Notes/.attachments.{note_id}/{attachment_filename}`
# Retrieve the note to verify content
retrieved_note = nc_client.notes_get_note(note_id=note_id)
print("Retrieved note content:")
print(retrieved_note["content"])
logger.info("Retrieved note content:")
logger.info(retrieved_note["content"])
# Verify the image attachment can be retrieved
content, mime_type = nc_client.get_note_attachment(
@@ -120,14 +123,14 @@ Files path: `/Notes/.attachments.{note_id}/{attachment_filename}`
assert content == image_content, "Attachment content mismatch"
assert mime_type.startswith("image/"), f"Expected image mime type, got {mime_type}"
print("Image attachment verified")
logger.info("Image attachment verified")
finally:
# Cleanup
if note_id:
print(f"Cleaning up - deleting note ID: {note_id}")
logger.info(f"Cleaning up - deleting note ID: {note_id}")
try:
nc_client.notes_delete_note(note_id=note_id)
print(f"Note {note_id} deleted")
logger.info(f"Note {note_id} deleted")
except Exception as e:
print(f"Error during cleanup: {e}")
logger.info(f"Error during cleanup: {e}")