from unittest.mock import patch, MagicMock from pathlib import Path from storage import R2Storage def _make_storage(): return R2Storage( account_id="acct", access_key="ak", secret_key="sk", bucket="karaoke", public_base_url="https://pub.example.com", ) @patch("storage.boto3.client") def test_upload_calls_put_object(mock_boto): mock_s3 = MagicMock() mock_boto.return_value = mock_s3 storage = _make_storage() storage.upload(b"data", "karaoke/abc.mp3", content_type="audio/mpeg") mock_s3.put_object.assert_called_once() kwargs = mock_s3.put_object.call_args.kwargs assert kwargs["Bucket"] == "karaoke" assert kwargs["Key"] == "karaoke/abc.mp3" assert kwargs["Body"] == b"data" assert kwargs["ContentType"] == "audio/mpeg" @patch("storage.boto3.client") def test_upload_file_streams_from_path(mock_boto, tmp_path): mock_s3 = MagicMock() mock_boto.return_value = mock_s3 storage = _make_storage() p = tmp_path / "x.mp3" p.write_bytes(b"abc") storage.upload_file(p, "karaoke/abc.mp3") mock_s3.upload_file.assert_called_once_with( Filename=str(p), Bucket="karaoke", Key="karaoke/abc.mp3", ExtraArgs={"ContentType": "audio/mpeg"}, ) def test_public_url_composes_base_and_key(): storage = _make_storage() assert storage.public_url("karaoke/abc.mp3") == "https://pub.example.com/karaoke/abc.mp3" # --- SupabaseStorage --------------------------------------------------------- from storage import SupabaseStorage def _make_supabase_storage(): client = MagicMock() storage = SupabaseStorage( client=client, bucket="karaoke", public_base_url="https://x.supabase.co/storage/v1/object/public/karaoke", ) return storage, client def test_supabase_upload_calls_storage_from_upload(): storage, client = _make_supabase_storage() storage.upload(b"data", "abc.mp3", content_type="audio/mpeg") client.storage.from_.assert_called_with("karaoke") client.storage.from_.return_value.upload.assert_called_once() kwargs = client.storage.from_.return_value.upload.call_args.kwargs assert kwargs["path"] == "abc.mp3" assert kwargs["file"] == b"data" assert kwargs["file_options"]["content-type"] == "audio/mpeg" def test_supabase_upload_file_reads_path(tmp_path): storage, client = _make_supabase_storage() p = tmp_path / "x.mp3" p.write_bytes(b"abc") storage.upload_file(p, "abc.mp3") client.storage.from_.return_value.upload.assert_called_once() kwargs = client.storage.from_.return_value.upload.call_args.kwargs assert kwargs["file"] == b"abc" def test_supabase_public_url(): storage, _ = _make_supabase_storage() assert storage.public_url("abc.mp3") == "https://x.supabase.co/storage/v1/object/public/karaoke/abc.mp3" def test_supabase_delete_calls_remove(): storage, client = _make_supabase_storage() storage.delete("abc.mp3") client.storage.from_.return_value.remove.assert_called_once_with(["abc.mp3"])