Files

160 lines
5.7 KiB
Python
Raw Permalink Normal View History

import io
import os
import sys
import unittest
from unittest import mock
sys.path.insert(0, os.path.dirname(__file__))
from _helpers import TempDirMixin
from app import db, image_studio, image_studio_export, image_studio_generation, image_studio_images
class ImageStudioE2ETests(TempDirMixin, unittest.TestCase):
def _png_bytes(self, color=(80, 130, 220)):
from PIL import Image
output = io.BytesIO()
Image.new("RGB", (32, 32), color).save(output, format="PNG")
return output.getvalue()
def _config(self, temp_dir):
return {
"data_dir": temp_dir,
"db_path": os.path.join(temp_dir, "cmshopee.db"),
"image_dir": os.path.join(temp_dir, "images"),
"ai": {
"backend": "cmhub",
"image_concurrency": 2,
"retry": 0,
"resolution": "1k",
"jpg_quality": 90,
"cmhub": {
"base_url": "https://cmhub.example.com",
"image_alias": "image-hd",
"connect_timeout": 3,
"download_with_curl": "false",
},
},
}
def _runtime(self):
return {
"base_url": "https://cmhub.example.com",
"api_key": "sk-test",
"alias": "image-hd",
"connect_timeout": 3,
"use_system_proxy": False,
"download_with_curl": "false",
}
def test_mock_ai_studio_project_to_export_flow(self):
with self.make_temp_dir() as temp_dir:
cfg = self._config(temp_dir)
db.init_db(cfg["db_path"])
project = image_studio.create_or_get_project(
account_alias="alias",
account_slug="alias_slug",
item_id="51100639510",
draft_prompt="完整提示词",
path=cfg["db_path"],
)
original = image_studio.sync_original_asset_urls(
project.id,
[{"index": 1, "src": "https://cdn.example.com/original.png"}],
path=cfg["db_path"],
)[0]
remote = image_studio_images.RemoteImage(
url=original.remote_url,
content=self._png_bytes(),
content_type="image/png",
final_url=original.remote_url,
redirected=False,
)
with mock.patch("app.image_studio_images.download_remote_image", return_value=remote):
source = image_studio_images.download_original_asset(
original.id,
path=cfg["db_path"],
config=cfg,
)
submitted = []
def fake_submit(method, url, api_key, **kwargs):
task_id = f"cmhub-task-{len(submitted) + 1}"
submitted.append(task_id)
return {
"task_id": task_id,
"status": "queued",
"call_id": f"call-{len(submitted)}",
"points_cost": 2,
"points_balance": 100 - len(submitted) * 2,
}
def fake_poll(method, url, api_key, **kwargs):
task_id = url.rsplit("/", 1)[-1]
return {
"task_id": task_id,
"status": "succeeded",
"result": {"image_url": f"https://cdn.example.com/{task_id}.png"},
}
with mock.patch("app.image_studio_generation._runtime", return_value=self._runtime()), \
mock.patch(
"app.image_studio_generation.ai._cmhub_call_with_retry",
side_effect=fake_submit,
), \
mock.patch("app.image_studio_generation.ai._cmhub_call_once", side_effect=fake_poll), \
mock.patch(
"app.image_studio_generation.ai._download_cmhub_image_with_retry",
return_value=(self._png_bytes(color=(10, 200, 120)), 0.1),
):
summary = image_studio_generation.generate_image_jobs(
project.id,
source.id,
"完整提示词",
2,
config=cfg,
path=cfg["db_path"],
)
self.assertEqual(2, summary["success"])
generated = image_studio.list_assets(project.id, kind="generated_main", path=cfg["db_path"])
self.assertEqual(2, len(generated))
image_studio.replace_selections(
project.id,
"main",
[asset.id for asset in generated],
path=cfg["db_path"],
)
image_studio.replace_selections(project.id, "detail", [source.id], path=cfg["db_path"])
export_parent = os.path.join(temp_dir, "exports")
os.makedirs(export_parent)
result = image_studio_export.export_project_selection(
project.id,
export_parent,
path=cfg["db_path"],
config=cfg,
)
self.assertEqual(2, result.main_count)
self.assertEqual(1, result.detail_count)
self.assertEqual(
[
"51100639510_主图_1.jpg",
"51100639510_主图_2.jpg",
"51100639510_详情图_1.jpg",
],
[os.path.basename(item.output_path) for item in result.files],
)
self.assertTrue(all(os.path.isfile(item.output_path) for item in result.files))
self.assert_removed(temp_dir)
if __name__ == "__main__":
unittest.main()