From e1de793af847cec6e6ee999941b3b5063c21938f Mon Sep 17 00:00:00 2001 From: Chris Coutinho Date: Tue, 6 May 2025 14:45:41 +0200 Subject: [PATCH] wip: tests --- nextcloud_mcp_server/client.py | 48 +++-------- pyproject.toml | 3 + tests/test_client.py | 118 +++++++++++++------------- tests/test_embedded_images.py | 19 +++-- tests/test_note_attachment_cleanup.py | 25 +++--- tests/test_note_image_integration.py | 25 +++--- 6 files changed, 113 insertions(+), 125 deletions(-) diff --git a/nextcloud_mcp_server/client.py b/nextcloud_mcp_server/client.py index e143485..8e0bb82 100644 --- a/nextcloud_mcp_server/client.py +++ b/nextcloud_mcp_server/client.py @@ -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 diff --git a/pyproject.toml b/pyproject.toml index 646e43e..1f1643b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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\"')" ] diff --git a/tests/test_client.py b/tests/test_client.py index a8a576e..70b5ed4 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -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}") diff --git a/tests/test_embedded_images.py b/tests/test_embedded_images.py index 6246164..12436d8 100644 --- a/tests/test_embedded_images.py +++ b/tests/test_embedded_images.py @@ -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) diff --git a/tests/test_note_attachment_cleanup.py b/tests/test_note_attachment_cleanup.py index cf8f2cf..61de4d6 100644 --- a/tests/test_note_attachment_cleanup.py +++ b/tests/test_note_attachment_cleanup.py @@ -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: diff --git a/tests/test_note_image_integration.py b/tests/test_note_image_integration.py index 26225ce..0e8424d 100644 --- a/tests/test_note_image_integration.py +++ b/tests/test_note_image_integration.py @@ -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}")