Files
AEmotionStudio-ComfyUI-Disc…/tests/test_security_fixes.py
T
AEmotionStudioandClaude Opus 4.5 a208cd482b refactor(phase2): extract shared utilities and reduce node duplication
- Create shared/filename_utils.py for date/time/dimension filename building
- Create shared/path_utils.py for output directory handling
- Create shared/discord/message_builder.py for Discord message construction
- Create shared/discord/cdn_extractor.py for CDN URL extraction
- Refactor image_node.py to use shared utilities (-161 lines, 16.3%)
- Refactor video_node.py to use shared utilities (-361 lines, 23.1%)
- Fix setup_logging missing from logging_config.py
- Fix test imports to use new module paths (nodes.* instead of discord_*_node)
- Total reduction: 522 lines (20.5%), exceeding PRD target of ~200 lines

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 23:33:10 -08:00

126 lines
4.6 KiB
Python

import sys
import os
import unittest
from unittest.mock import patch, MagicMock
import shutil
import tempfile
# Mock dependencies before importing project modules
sys.modules["torch"] = MagicMock()
sys.modules["numpy"] = MagicMock()
sys.modules["cv2"] = MagicMock()
sys.modules["PIL"] = MagicMock()
sys.modules["PIL.Image"] = MagicMock()
sys.modules["PIL.PngImagePlugin"] = MagicMock()
sys.modules["comfy"] = MagicMock()
sys.modules["comfy.cli_args"] = MagicMock()
sys.modules["comfy.utils"] = MagicMock()
sys.modules["server"] = MagicMock()
# Mock folder_paths
mock_folder_paths = MagicMock()
sys.modules["folder_paths"] = mock_folder_paths
# Add parent directory to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Import the node
from nodes.video_node import DiscordSendSaveVideo
class TestTempFileLeak(unittest.TestCase):
def setUp(self):
# Create a real temporary directory for our test
self.test_dir = tempfile.mkdtemp()
self.output_dir = os.path.join(self.test_dir, "output")
self.temp_dir = os.path.join(self.test_dir, "temp")
os.makedirs(self.output_dir)
os.makedirs(self.temp_dir)
# Configure folder_paths mock
mock_folder_paths.get_output_directory.return_value = self.output_dir
mock_folder_paths.get_temp_directory.return_value = self.temp_dir
# Mock get_save_image_path to return predictable paths
# full_output_folder, filename, counter, subfolder, filename_prefix
mock_folder_paths.get_save_image_path.return_value = (
self.output_dir, "ComfyUI-Video", 1, "", "ComfyUI-Video"
)
# Instantiate the node
self.node = DiscordSendSaveVideo()
# Create a dummy image tensor mock
self.dummy_image = MagicMock()
self.dummy_image.shape = (512, 512, 3) # height, width, channels
# Mock tensor_to_numpy_uint8 in discordsend_utils
self.patcher_numpy = patch("nodes.video_node.tensor_to_numpy_uint8")
self.mock_numpy_conv = self.patcher_numpy.start()
# Return a dummy numpy array
import numpy as np
self.mock_numpy_conv.return_value = np.zeros((512, 512, 3), dtype=np.uint8)
def tearDown(self):
self.patcher_numpy.stop()
shutil.rmtree(self.test_dir)
@patch("nodes.video_node.subprocess.Popen")
@patch("nodes.video_node.subprocess.run")
@patch("nodes.video_node.send_to_discord_with_retry")
@patch("nodes.video_node.Image")
@patch("nodes.video_node.os.path.getsize")
@patch("nodes.video_node.validate_video_for_discord")
def test_temp_file_leak(self, mock_validate, mock_getsize, mock_image, mock_send, mock_run, mock_popen):
# Setup mocks
mock_process = MagicMock()
mock_process.returncode = 0
mock_process.stdin = MagicMock()
mock_popen.return_value = mock_process
mock_send.return_value.status_code = 200
mock_send.return_value.json.return_value = {}
mock_getsize.return_value = 1024 * 1024 # 1MB
mock_validate.return_value = (True, "Valid")
# Create a fake output file that subprocess would have created
fake_output_path = os.path.join(self.output_dir, "ComfyUI-Video_00001.mp4")
with open(fake_output_path, "wb") as f:
f.write(b"fake video content")
# Mock subprocess.run to simulate creation of optimized file
def side_effect_run(args, **kwargs):
# The last argument is the output file path
output_file = args[-1]
if "discord_optimized_" in output_file:
# Create the file
with open(output_file, "wb") as f:
f.write(b"optimized video content")
return MagicMock(returncode=0)
mock_run.side_effect = side_effect_run
# Run the node
self.node.save_video(
images=[self.dummy_image],
send_to_discord=True,
webhook_url="https://discord.com/api/webhooks/123/abc",
format="video/h264-mp4",
save_output=True
)
# Check if any file in temp_dir contains "discord_optimized_"
temp_files = os.listdir(self.temp_dir)
optimized_files = [f for f in temp_files if "discord_optimized_" in f]
print(f"Files remaining in temp dir: {temp_files}")
# This assertion is expected to FAIL if the leak exists (because we want 0 files)
# Or pass if we assert > 0 to prove the leak.
# After fix, we expect 0 files.
self.assertEqual(len(optimized_files), 0, "Temporary optimized file should have been cleaned up")
if __name__ == "__main__":
unittest.main()