import pytest import logging import time import uuid from httpx import HTTPStatusError from nextcloud_mcp_server.client import NextcloudClient logger = logging.getLogger(__name__) # Mark all tests in this module as integration tests pytestmark = pytest.mark.integration def test_category_change_cleans_up_old_attachments_directory(nc_client: NextcloudClient): """ Tests that when a note's category is changed, the old attachment directory is properly cleaned up. """ note_id = None initial_category = "CategoryTest1" new_category = "CategoryTest2" unique_suffix = uuid.uuid4().hex[:8] note_title = f"Category Cleanup Test {unique_suffix}" attachment_filename = f"cleanup_test_{unique_suffix}.txt" attachment_content = f"Content for {attachment_filename}".encode('utf-8') try: # 1. Create note with initial category logger.info(f"Creating note '{note_title}' in category '{initial_category}'") created_note = nc_client.notes_create_note( title=note_title, content="Initial content", category=initial_category ) note_id = created_note["id"] etag1 = created_note["etag"] logger.info(f"Note created with ID: {note_id}, Etag: {etag1}") time.sleep(1) # 2. Add attachment (passing initial category) logger.info(f"Adding attachment '{attachment_filename}' to note {note_id} (in {initial_category})") upload_response = nc_client.add_note_attachment( note_id=note_id, filename=attachment_filename, content=attachment_content, category=initial_category, mime_type="text/plain" ) assert upload_response["status_code"] in [201, 204] logger.info("Attachment added successfully.") time.sleep(1) # 3. Verify attachment retrieval from initial category logger.info(f"Verifying attachment retrieval from initial category '{initial_category}'") retrieved_content1, _ = nc_client.get_note_attachment(note_id=note_id, filename=attachment_filename, category=initial_category) assert retrieved_content1 == attachment_content logger.info("Attachment retrieved successfully from initial category.") # 4. Construct and check the WebDAV path for the initial category's attachment directory initial_webdav_path = f"Notes/{initial_category}/.attachments.{note_id}" logger.info(f"Initial WebDAV path for attachments: {initial_webdav_path}") # Here we would check if the directory exists, but the WebDAV client doesn't directly # expose directory listing functionality, so we'll infer from attachment retrieval success # 5. Update note category logger.info(f"Updating note {note_id} category from '{initial_category}' to '{new_category}'") current_note_data = nc_client.notes_get_note(note_id=note_id) current_etag = current_note_data["etag"] updated_note = nc_client.notes_update_note( note_id=note_id, etag=current_etag, category=new_category, title=note_title, content="Updated content" ) etag3 = updated_note["etag"] assert updated_note["category"] == new_category logger.info(f"Note category updated successfully. New Etag: {etag3}") time.sleep(1) # 6. Verify attachment retrieval from new category logger.info(f"Verifying attachment retrieval from new category '{new_category}'") retrieved_content2, _ = nc_client.get_note_attachment(note_id=note_id, filename=attachment_filename, category=new_category) assert retrieved_content2 == attachment_content logger.info("Attachment retrieved successfully from new category.") # 7. Try to retrieve from old category - this should fail logger.info(f"Trying to retrieve attachment from old category '{initial_category}' - should fail") try: nc_client.get_note_attachment(note_id=note_id, filename=attachment_filename, category=initial_category) # If we get here, it means the old directory still exists (a problem) logger.error("ISSUE DETECTED: Was able to retrieve attachment from old category path!") assert False, "Old category attachment directory still exists and accessible!" except HTTPStatusError as e: # This is the expected outcome - old directory should be gone logger.info(f"Correctly got error accessing old category path: {e.response.status_code}") assert e.response.status_code == 404, f"Expected 404, got {e.response.status_code}" logger.info("Verified old category attachment directory is not accessible (good!)") # 7.1 Directly check old attachment directory existence using WebDAV PROPFIND logger.info(f"Directly checking if old attachment directory exists in WebDAV") webdav_base = nc_client._get_webdav_base_path() old_attachment_dir_path = f"{webdav_base}/Notes/{initial_category}/.attachments.{note_id}" propfind_headers = {"Depth": "0", "OCS-APIRequest": "true"} try: propfind_resp = nc_client._client.request("PROPFIND", old_attachment_dir_path, headers=propfind_headers) status = propfind_resp.status_code if status in [200, 207]: # Success codes indicate the directory exists (a problem) logger.error(f"Old attachment directory still exists! PROPFIND returned {status}") assert False, f"Expected old attachment directory to be gone, but it still exists (PROPFIND returned {status})!" # If we got another status code (like 404), it's also good - the directory doesn't exist logger.info(f"Verified old attachment directory does not exist (PROPFIND returned {status})") except HTTPStatusError as e: # 404 is expected - directory should not exist assert e.response.status_code == 404, f"Expected PROPFIND to fail with 404, got {e.response.status_code}" logger.info(f"Verified old attachment directory does not exist via PROPFIND (404 received)") finally: # 8. Cleanup: Delete the note if note_id: logger.info(f"Cleaning up note ID: {note_id}") try: nc_client.notes_delete_note(note_id=note_id) logger.info(f"Note {note_id} deleted.") time.sleep(1) # 9. Verify both old and new attachment paths are gone logger.info("Verifying all attachment paths are gone") with pytest.raises(HTTPStatusError) as excinfo_new: nc_client.get_note_attachment(note_id=note_id, filename=attachment_filename, category=new_category) assert excinfo_new.value.response.status_code == 404 with pytest.raises(HTTPStatusError) as excinfo_old: nc_client.get_note_attachment(note_id=note_id, filename=attachment_filename, category=initial_category) assert excinfo_old.value.response.status_code == 404 # 9.1 Directly verify directories don't exist using WebDAV PROPFIND logger.info("Directly verifying attachment directories don't exist via PROPFIND") webdav_base = nc_client._get_webdav_base_path() # Check new category attachment directory new_attachment_dir_path = f"{webdav_base}/Notes/{new_category}/.attachments.{note_id}" propfind_headers = {"Depth": "0", "OCS-APIRequest": "true"} try: propfind_resp = nc_client._client.request("PROPFIND", new_attachment_dir_path, headers=propfind_headers) status = propfind_resp.status_code if status in [200, 207]: # Success codes indicate the directory exists (a problem) logger.error(f"New category attachment directory still exists! PROPFIND returned {status}") assert False, f"Expected new category attachment directory to be gone, but it still exists (PROPFIND returned {status})!" # If we got another status code (like 404), it's also good - the directory doesn't exist logger.info(f"Verified new category attachment directory does not exist (PROPFIND returned {status})") except HTTPStatusError as e: assert e.response.status_code == 404, f"Expected PROPFIND to fail with 404, got {e.response.status_code}" logger.info("Verified new category attachment directory is gone via PROPFIND") # Check old category attachment directory old_attachment_dir_path = f"{webdav_base}/Notes/{initial_category}/.attachments.{note_id}" try: propfind_resp = nc_client._client.request("PROPFIND", old_attachment_dir_path, headers=propfind_headers) status = propfind_resp.status_code if status in [200, 207]: # Success codes indicate the directory exists (a problem) logger.error(f"Old category attachment directory still exists! PROPFIND returned {status}") assert False, f"Expected old category attachment directory to be gone, but it still exists (PROPFIND returned {status})!" # If we got another status code (like 404), it's also good - the directory doesn't exist logger.info(f"Verified old category attachment directory does not exist (PROPFIND returned {status})") except HTTPStatusError as e: assert e.response.status_code == 404, f"Expected PROPFIND to fail with 404, got {e.response.status_code}" logger.info("Verified old category attachment directory is gone via PROPFIND") logger.info("Verified all attachment directories are properly cleaned up.") except Exception as e: logger.error(f"Error during cleanup for note {note_id}: {e}")