mirror of
https://github.com/langgenius/dify.git
synced 2026-05-03 17:08:03 +08:00
WIP: huamninput email sending
This commit is contained in:
@ -0,0 +1,59 @@
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from core.app.apps.workflow_app_runner import WorkflowBasedAppRunner
|
||||
from core.app.entities.queue_entities import QueueWorkflowPausedEvent
|
||||
from core.workflow.entities.pause_reason import HumanInputRequired
|
||||
from core.workflow.graph_events.graph import GraphRunPausedEvent
|
||||
|
||||
|
||||
class _DummyQueueManager:
|
||||
def __init__(self):
|
||||
self.published = []
|
||||
|
||||
def publish(self, event, _from):
|
||||
self.published.append(event)
|
||||
|
||||
|
||||
class _DummyRuntimeState:
|
||||
def get_paused_nodes(self):
|
||||
return ["node-1"]
|
||||
|
||||
|
||||
class _DummyGraphEngine:
|
||||
def __init__(self):
|
||||
self.graph_runtime_state = _DummyRuntimeState()
|
||||
|
||||
|
||||
class _DummyWorkflowEntry:
|
||||
def __init__(self):
|
||||
self.graph_engine = _DummyGraphEngine()
|
||||
|
||||
|
||||
def test_handle_pause_event_enqueues_email_task(monkeypatch: pytest.MonkeyPatch):
|
||||
queue_manager = _DummyQueueManager()
|
||||
runner = WorkflowBasedAppRunner(queue_manager=queue_manager, app_id="app-id")
|
||||
workflow_entry = _DummyWorkflowEntry()
|
||||
|
||||
reason = HumanInputRequired(
|
||||
form_id="form-123",
|
||||
form_content="content",
|
||||
inputs=[],
|
||||
actions=[],
|
||||
node_id="node-1",
|
||||
node_title="Review",
|
||||
)
|
||||
event = GraphRunPausedEvent(reasons=[reason], outputs={})
|
||||
|
||||
email_task = MagicMock()
|
||||
monkeypatch.setattr("core.app.apps.workflow_app_runner.dispatch_human_input_email_task", email_task)
|
||||
|
||||
runner._handle_event(workflow_entry, event)
|
||||
|
||||
email_task.apply_async.assert_called_once()
|
||||
kwargs = email_task.apply_async.call_args.kwargs["kwargs"]
|
||||
assert kwargs["form_id"] == "form-123"
|
||||
assert kwargs["node_title"] == "Review"
|
||||
|
||||
assert any(isinstance(evt, QueueWorkflowPausedEvent) for evt in queue_manager.published)
|
||||
@ -0,0 +1,27 @@
|
||||
import pytest
|
||||
|
||||
from core.workflow.nodes.human_input.entities import EmailDeliveryConfig, EmailRecipients
|
||||
|
||||
|
||||
def test_replace_url_placeholder_with_value():
|
||||
config = EmailDeliveryConfig(
|
||||
recipients=EmailRecipients(),
|
||||
subject="Subject",
|
||||
body="Click here {{#url#}} to open.",
|
||||
)
|
||||
|
||||
result = config.body_with_url("https://example.com/link")
|
||||
|
||||
assert result == "Click here https://example.com/link to open."
|
||||
|
||||
|
||||
def test_replace_url_placeholder_missing_value():
|
||||
config = EmailDeliveryConfig(
|
||||
recipients=EmailRecipients(),
|
||||
subject="Subject",
|
||||
body="No link {{#url#}} available.",
|
||||
)
|
||||
|
||||
result = config.body_with_url(None)
|
||||
|
||||
assert result == "No link available."
|
||||
@ -0,0 +1,65 @@
|
||||
import types
|
||||
from collections.abc import Sequence
|
||||
|
||||
import pytest
|
||||
|
||||
from tasks import mail_human_input_delivery_task as task_module
|
||||
|
||||
|
||||
class _DummyMail:
|
||||
def __init__(self):
|
||||
self.sent: list[dict[str, str]] = []
|
||||
self._inited = True
|
||||
|
||||
def is_inited(self) -> bool:
|
||||
return self._inited
|
||||
|
||||
def send(self, *, to: str, subject: str, html: str):
|
||||
self.sent.append({"to": to, "subject": subject, "html": html})
|
||||
|
||||
|
||||
class _DummySession:
|
||||
def __enter__(self):
|
||||
return None
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
return False
|
||||
|
||||
|
||||
def _build_job(recipient_count: int = 1) -> task_module._EmailDeliveryJob:
|
||||
recipients: list[task_module._EmailRecipient] = []
|
||||
for idx in range(recipient_count):
|
||||
recipients.append(task_module._EmailRecipient(email=f"user{idx}@example.com", token=f"token-{idx}"))
|
||||
|
||||
return task_module._EmailDeliveryJob(
|
||||
form_id="form-1",
|
||||
workflow_run_id="run-1",
|
||||
subject="Subject for {{ form_token }}",
|
||||
body="Body for {{ form_link }}",
|
||||
form_content="content",
|
||||
recipients=recipients,
|
||||
)
|
||||
|
||||
|
||||
def test_dispatch_human_input_email_task_sends_to_each_recipient(monkeypatch: pytest.MonkeyPatch):
|
||||
mail = _DummyMail()
|
||||
|
||||
def fake_render(template: str, substitutions: dict[str, str]) -> str:
|
||||
return template.replace("{{ form_token }}", substitutions["form_token"]).replace(
|
||||
"{{ form_link }}", substitutions["form_link"]
|
||||
)
|
||||
|
||||
monkeypatch.setattr(task_module, "mail", mail)
|
||||
monkeypatch.setattr(task_module, "render_email_template", fake_render)
|
||||
jobs: Sequence[task_module._EmailDeliveryJob] = [_build_job(recipient_count=2)]
|
||||
monkeypatch.setattr(task_module, "_load_email_jobs", lambda _session, _form_id: jobs)
|
||||
|
||||
task_module.dispatch_human_input_email_task(
|
||||
form_id="form-1",
|
||||
node_title="Approve",
|
||||
session_factory=lambda: _DummySession(),
|
||||
)
|
||||
|
||||
assert len(mail.sent) == 2
|
||||
assert all(payload["subject"].startswith("Subject for token-") for payload in mail.sent)
|
||||
assert all("Body for" in payload["html"] for payload in mail.sent)
|
||||
Reference in New Issue
Block a user