test_load_file_attachment.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. """Integration tests for LoadFileAttachment tool."""
  2. import os
  3. import tempfile
  4. from pathlib import Path
  5. import pytest
  6. from agency_swarm import Agent
  7. from agency_swarm.tools.built_in import LoadFileAttachment
  8. @pytest.fixture
  9. def agent_with_file_loader():
  10. """Create an agent with LoadFileAttachment tool."""
  11. return Agent(
  12. name="FileLoaderAgent",
  13. description="Test agent with file loading capability",
  14. instructions="Load files when requested",
  15. tools=[LoadFileAttachment],
  16. )
  17. @pytest.fixture
  18. def temp_test_dir_with_files():
  19. """Create a temporary directory with test files."""
  20. with tempfile.TemporaryDirectory() as tmpdir:
  21. temp_path = Path(tmpdir)
  22. # Create a simple PNG image (1x1 red pixel)
  23. png_file = temp_path / "test.png"
  24. # PNG header + 1x1 red pixel
  25. png_data = (
  26. b"\x89PNG\r\n\x1a\n" # PNG signature
  27. b"\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01"
  28. b"\x08\x02\x00\x00\x00\x90wS\xde"
  29. b"\x00\x00\x00\x0cIDATx\x9cc\xf8\xcf\xc0\x00\x00\x00\x03\x00\x01\x00\x00\x00\x00"
  30. b"\x00\x00\x00\x00IEND\xaeB`\x82"
  31. )
  32. png_file.write_bytes(png_data)
  33. # Create a JPEG file marker
  34. jpg_file = temp_path / "test.jpg"
  35. # Minimal valid JPEG
  36. jpg_data = b"\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xd9"
  37. jpg_file.write_bytes(jpg_data)
  38. # Create a PDF file marker
  39. pdf_file = temp_path / "test.pdf"
  40. pdf_file.write_text("%PDF-1.4\n%%EOF")
  41. yield temp_path
  42. class TestLoadFileAttachmentBasics:
  43. """Test basic file loading functionality."""
  44. @pytest.mark.asyncio
  45. async def test_load_pdf_file(self, agent_with_file_loader, temp_test_dir_with_files):
  46. """Test loading a PDF file."""
  47. pdf_file = temp_test_dir_with_files / "test.pdf"
  48. tool = LoadFileAttachment(path=pdf_file)
  49. tool._caller_agent = agent_with_file_loader
  50. result = await tool.run()
  51. # Should return a ToolOutputFileContent object
  52. assert hasattr(result, "type")
  53. assert result.type == "file"
  54. @pytest.mark.asyncio
  55. async def test_load_png_image(self, agent_with_file_loader, temp_test_dir_with_files):
  56. """Test loading a PNG image file."""
  57. png_file = temp_test_dir_with_files / "test.png"
  58. tool = LoadFileAttachment(path=png_file)
  59. tool._caller_agent = agent_with_file_loader
  60. result = await tool.run()
  61. # Should return a ToolOutputImage object with image_url
  62. assert hasattr(result, "image_url") or hasattr(result, "file_id")
  63. assert hasattr(result, "detail")
  64. @pytest.mark.asyncio
  65. async def test_load_jpeg_image(self, agent_with_file_loader, temp_test_dir_with_files):
  66. """Test loading a JPEG image file."""
  67. jpg_file = temp_test_dir_with_files / "test.jpg"
  68. tool = LoadFileAttachment(path=jpg_file)
  69. tool._caller_agent = agent_with_file_loader
  70. result = await tool.run()
  71. # Should return a ToolOutputImage object with image_url
  72. assert hasattr(result, "image_url") or hasattr(result, "file_id")
  73. assert hasattr(result, "detail")
  74. class TestLoadFileAttachmentPathResolution:
  75. """Test path resolution functionality."""
  76. @pytest.mark.asyncio
  77. async def test_absolute_path(self, agent_with_file_loader, temp_test_dir_with_files):
  78. """Test loading file with absolute path."""
  79. pdf_file = temp_test_dir_with_files / "test.pdf"
  80. tool = LoadFileAttachment(path=pdf_file)
  81. tool._caller_agent = agent_with_file_loader
  82. result = await tool.run()
  83. assert hasattr(result, "type")
  84. assert result.type == "file"
  85. @pytest.mark.asyncio
  86. async def test_relative_path(self, agent_with_file_loader, temp_test_dir_with_files):
  87. """Test loading file with relative path (from CWD)."""
  88. # Save current directory
  89. original_cwd = Path.cwd()
  90. try:
  91. # Change to temp directory
  92. os.chdir(temp_test_dir_with_files)
  93. # Use relative path
  94. tool = LoadFileAttachment(path=Path("test.pdf"))
  95. tool._caller_agent = agent_with_file_loader
  96. result = await tool.run()
  97. assert hasattr(result, "type")
  98. assert result.type == "file"
  99. finally:
  100. # Restore original directory
  101. os.chdir(original_cwd)
  102. class TestLoadFileAttachmentErrorHandling:
  103. """Test error handling and helpful messages."""
  104. @pytest.mark.asyncio
  105. async def test_file_not_found_with_directory_listing(self, agent_with_file_loader, temp_test_dir_with_files):
  106. """Test that missing file shows available files in directory."""
  107. nonexistent_file = temp_test_dir_with_files / "does_not_exist.pdf"
  108. tool = LoadFileAttachment(path=nonexistent_file)
  109. tool._caller_agent = agent_with_file_loader
  110. result = await tool.run()
  111. # Should be a string with error message and file listing
  112. assert isinstance(result, str)
  113. assert "File not found" in result
  114. assert "Available files" in result
  115. # Should list the existing files
  116. assert "test.pdf" in result
  117. assert "test.png" in result
  118. @pytest.mark.asyncio
  119. async def test_file_not_found_empty_directory(self, agent_with_file_loader):
  120. """Test error message when directory is empty."""
  121. with tempfile.TemporaryDirectory() as tmpdir:
  122. temp_path = Path(tmpdir)
  123. nonexistent_file = temp_path / "missing.pdf"
  124. tool = LoadFileAttachment(path=nonexistent_file)
  125. tool._caller_agent = agent_with_file_loader
  126. result = await tool.run()
  127. assert isinstance(result, str)
  128. assert "File not found" in result
  129. assert "is empty" in result
  130. class TestLoadFileAttachmentImageFormats:
  131. """Test various image format detection."""
  132. @pytest.mark.asyncio
  133. async def test_various_image_extensions(self, agent_with_file_loader):
  134. """Test that various image extensions are recognized."""
  135. with tempfile.TemporaryDirectory() as tmpdir:
  136. temp_path = Path(tmpdir)
  137. # Test different image extensions that have MIME type support
  138. image_extensions = [".gif", ".bmp"]
  139. for ext in image_extensions:
  140. # Create a dummy file
  141. image_file = temp_path / f"test{ext}"
  142. image_file.write_bytes(b"dummy image data")
  143. tool = LoadFileAttachment(path=image_file)
  144. tool._caller_agent = agent_with_file_loader
  145. result = await tool.run()
  146. # Should be treated as image and return ToolOutputImage
  147. assert hasattr(result, "image_url") or hasattr(result, "file_id"), (
  148. f"Extension {ext} should return image"
  149. )
  150. assert hasattr(result, "detail")
  151. @pytest.mark.asyncio
  152. async def test_case_insensitive_extension(self, agent_with_file_loader):
  153. """Test that image detection is case-insensitive."""
  154. with tempfile.TemporaryDirectory() as tmpdir:
  155. temp_path = Path(tmpdir)
  156. # Create files with uppercase extensions
  157. png_upper = temp_path / "test.PNG"
  158. png_upper.write_bytes(b"dummy")
  159. jpg_upper = temp_path / "test.JPG"
  160. jpg_upper.write_bytes(b"dummy")
  161. for file_path in [png_upper, jpg_upper]:
  162. tool = LoadFileAttachment(path=file_path)
  163. tool._caller_agent = agent_with_file_loader
  164. result = await tool.run()
  165. # Should return ToolOutputImage
  166. assert hasattr(result, "image_url") or hasattr(result, "file_id")
  167. assert hasattr(result, "detail")