defmodule BDS.CSM009ThumbnailErrorHandlingTest do use ExUnit.Case, async: false alias BDS.Media.Thumbnails alias BDS.Repo setup do :ok = Ecto.Adapters.SQL.Sandbox.checkout(BDS.Repo) temp_dir = Path.join(System.tmp_dir!(), "bds-csm009-#{System.unique_integer([:positive])}") File.mkdir_p!(temp_dir) on_exit(fn -> File.rm_rf(temp_dir) end) {:ok, project} = BDS.Projects.create_project(%{name: "CSM009", data_path: temp_dir}) %{project: project, temp_dir: temp_dir} end test "ensure_thumbnails returns {:error, _} for a corrupt image instead of crashing", %{ project: project, temp_dir: temp_dir } do source_path = Path.join(temp_dir, "corrupt.jpg") File.write!(source_path, "not a real image") {:ok, media} = BDS.Media.import_media(%{project_id: project.id, source_path: source_path}) assert media.mime_type == "image/jpeg" Enum.each(Map.values(Thumbnails.thumbnail_paths(media)), fn path -> File.rm(Path.join(temp_dir, path)) end) result = Thumbnails.ensure_thumbnails(project, media) assert {:error, _reason} = result end test "ensure_thumbnails returns :ok for non-image media", %{project: project, temp_dir: temp_dir} do source_path = Path.join(temp_dir, "readme.txt") File.write!(source_path, "just text") {:ok, media} = BDS.Media.import_media(%{project_id: project.id, source_path: source_path}) assert Thumbnails.ensure_thumbnails(project, media) == :ok end test "ensure_thumbnails returns {:error, _} when source file is missing", %{ project: project, temp_dir: temp_dir } do source_path = Path.join(temp_dir, "sample.jpg") File.write!(source_path, tiny_jpeg_binary()) {:ok, media} = BDS.Media.import_media(%{project_id: project.id, source_path: source_path}) File.rm!(Path.join(temp_dir, media.file_path)) result = Thumbnails.ensure_thumbnails(project, media) assert {:error, _reason} = result end test "regenerate_thumbnails returns {:error, _} for corrupt source", %{ project: project, temp_dir: temp_dir } do source_path = Path.join(temp_dir, "corrupt2.jpg") File.write!(source_path, "not valid jpeg data") {:ok, media} = BDS.Media.import_media(%{project_id: project.id, source_path: source_path}) Enum.each(Map.values(Thumbnails.thumbnail_paths(media)), fn path -> File.rm(Path.join(temp_dir, path)) end) File.write!(Path.join(temp_dir, media.file_path), "not valid jpeg data") result = Thumbnails.regenerate_thumbnails(media.id) assert {:error, _reason} = result end test "regenerate_missing_thumbnails counts failures without crashing", %{ project: project, temp_dir: temp_dir } do source_path = Path.join(temp_dir, "good.jpg") File.write!(source_path, tiny_jpeg_binary()) {:ok, good_media} = BDS.Media.import_media(%{project_id: project.id, source_path: source_path}) corrupt_path = Path.join(temp_dir, "bad.jpg") File.write!(corrupt_path, "corrupt data") {:ok, bad_media} = BDS.Media.import_media(%{project_id: project.id, source_path: corrupt_path}) Enum.each(Map.values(Thumbnails.thumbnail_paths(good_media)), fn path -> File.rm(Path.join(temp_dir, path)) end) Enum.each(Map.values(Thumbnails.thumbnail_paths(bad_media)), fn path -> File.rm(Path.join(temp_dir, path)) end) File.write!(Path.join(temp_dir, bad_media.file_path), "corrupt data") result = Thumbnails.regenerate_missing_thumbnails(project.id) assert result.failed >= 1 assert result.processed >= 2 end test "import_media succeeds even when thumbnail generation fails for corrupt image", %{ project: project, temp_dir: temp_dir } do source_path = Path.join(temp_dir, "bad_import.jpg") File.write!(source_path, "not a real image at all") assert {:ok, media} = BDS.Media.import_media(%{project_id: project.id, source_path: source_path}) assert media.mime_type == "image/jpeg" assert Repo.get(BDS.Media.Media, media.id) != nil end defp tiny_jpeg_binary do Image.new!(3, 2, color: [255, 0, 0]) |> Image.write!(:memory, suffix: ".jpg", quality: 85) end end