mirror of
https://github.com/langgenius/dify.git
synced 2026-10-04 13:47:55 +08:00
refactor(api): extract workflow statistic query service (#41271)
This commit is contained in:
6 files changed
+409
-146
No files matched your search
@@ -5,13 +5,14 @@ from __future__ import annotations
|
||||
import uuid
|
||||
from collections.abc import Iterator
|
||||
from inspect import unwrap
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from flask import Flask
|
||||
from pydantic import ValidationError
|
||||
from sqlalchemy import Engine
|
||||
from sqlalchemy.orm import Session, sessionmaker
|
||||
from sqlalchemy.orm import Session
|
||||
from werkzeug.exceptions import BadRequest, NotFound
|
||||
|
||||
from controllers.console import console_ns
|
||||
@@ -70,7 +71,6 @@ from models import App, Site
|
||||
from models.account import Account, AccountStatus
|
||||
from models.engine import db
|
||||
from models.trigger import WorkflowWebhookTrigger
|
||||
from repositories.sqlalchemy_api_workflow_run_repository import DifyAPISQLAlchemyWorkflowRunRepository
|
||||
from services.app_site_service import (
|
||||
AppSiteAppNotFoundError,
|
||||
AppSiteChanges,
|
||||
@@ -106,6 +106,15 @@ def _make_app(
|
||||
return app
|
||||
|
||||
|
||||
def _make_request_context() -> RequestContext:
|
||||
return RequestContext(
|
||||
request_id="request-1",
|
||||
trace_id="trace-1",
|
||||
account_id=USER_ID,
|
||||
active_workspace_id=TENANT_ID,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def database_app() -> Iterator[Flask]:
|
||||
app = Flask(__name__)
|
||||
@@ -690,48 +699,162 @@ class TestWorkflowStatisticEndpoints:
|
||||
assert query.end is None
|
||||
|
||||
def test_workflow_daily_runs_statistic(self, database_app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
repository = DifyAPISQLAlchemyWorkflowRunRepository(
|
||||
session_maker=sessionmaker(bind=db.engine, expire_on_commit=False)
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
repository,
|
||||
"get_daily_runs_statistics",
|
||||
lambda **_kwargs: [{"date": "2024-01-01"}],
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
workflow_statistic_module.DifyAPIRepositoryFactory,
|
||||
"create_api_workflow_run_repository",
|
||||
lambda *_args, **_kwargs: repository,
|
||||
)
|
||||
service = MagicMock()
|
||||
service.get_daily_runs.return_value = [{"date": "2024-01-01", "runs": 2}]
|
||||
monkeypatch.setattr(
|
||||
workflow_statistic_module,
|
||||
"parse_time_range",
|
||||
lambda *_args, **_kwargs: (None, None),
|
||||
"application_services",
|
||||
lambda: SimpleNamespace(workflow_statistics=service),
|
||||
)
|
||||
self._patch_statistic_time_range(monkeypatch)
|
||||
|
||||
api = workflow_statistic_module.WorkflowDailyRunsStatistic()
|
||||
method = unwrap(api.get)
|
||||
request_context = _make_request_context()
|
||||
|
||||
with database_app.test_request_context("/"):
|
||||
account = _make_account()
|
||||
account.timezone = "UTC"
|
||||
response = method(api, WorkflowStatisticQuery(), account, app_model=_make_app("app-1", tenant_id="t1"))
|
||||
response = method(
|
||||
api,
|
||||
WorkflowStatisticQuery(),
|
||||
request_context,
|
||||
app_model=_make_app("app-1", tenant_id="t1"),
|
||||
)
|
||||
|
||||
assert response.get_json() == {"data": [{"date": "2024-01-01"}]}
|
||||
assert response == {"data": [{"date": "2024-01-01", "runs": 2}]}
|
||||
service.get_daily_runs.assert_called_once_with(
|
||||
request_context,
|
||||
app_id="app-1",
|
||||
start_date=None,
|
||||
end_date=None,
|
||||
timezone="UTC",
|
||||
)
|
||||
|
||||
def test_workflow_daily_terminals_statistic(self, database_app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
repository = DifyAPISQLAlchemyWorkflowRunRepository(
|
||||
session_maker=sessionmaker(bind=db.engine, expire_on_commit=False)
|
||||
service = MagicMock()
|
||||
service.get_daily_terminals.return_value = [{"date": "2024-01-02", "terminal_count": 3}]
|
||||
monkeypatch.setattr(
|
||||
workflow_statistic_module,
|
||||
"application_services",
|
||||
lambda: SimpleNamespace(workflow_statistics=service),
|
||||
)
|
||||
self._patch_statistic_time_range(monkeypatch)
|
||||
|
||||
api = workflow_statistic_module.WorkflowDailyTerminalsStatistic()
|
||||
method = unwrap(api.get)
|
||||
request_context = _make_request_context()
|
||||
|
||||
with database_app.test_request_context("/"):
|
||||
response = method(
|
||||
api,
|
||||
WorkflowStatisticQuery(),
|
||||
request_context,
|
||||
app_model=_make_app("app-1", tenant_id="t1"),
|
||||
)
|
||||
|
||||
assert response == {"data": [{"date": "2024-01-02", "terminal_count": 3}]}
|
||||
service.get_daily_terminals.assert_called_once_with(
|
||||
request_context,
|
||||
app_id="app-1",
|
||||
start_date=None,
|
||||
end_date=None,
|
||||
timezone="UTC",
|
||||
)
|
||||
|
||||
def test_workflow_daily_token_cost_statistic(
|
||||
self,
|
||||
database_app: Flask,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
service = MagicMock()
|
||||
service.get_daily_token_costs.return_value = [{"date": "2024-01-03", "token_count": 4}]
|
||||
monkeypatch.setattr(
|
||||
workflow_statistic_module,
|
||||
"application_services",
|
||||
lambda: SimpleNamespace(workflow_statistics=service),
|
||||
)
|
||||
self._patch_statistic_time_range(monkeypatch)
|
||||
|
||||
api = workflow_statistic_module.WorkflowDailyTokenCostStatistic()
|
||||
method = unwrap(api.get)
|
||||
request_context = _make_request_context()
|
||||
|
||||
with database_app.test_request_context("/"):
|
||||
response = method(
|
||||
api,
|
||||
WorkflowStatisticQuery(),
|
||||
request_context,
|
||||
app_model=_make_app("app-1", tenant_id="t1"),
|
||||
)
|
||||
|
||||
assert response == {"data": [{"date": "2024-01-03", "token_count": 4}]}
|
||||
service.get_daily_token_costs.assert_called_once_with(
|
||||
request_context,
|
||||
app_id="app-1",
|
||||
start_date=None,
|
||||
end_date=None,
|
||||
timezone="UTC",
|
||||
)
|
||||
|
||||
def test_workflow_average_app_interaction_statistic(
|
||||
self,
|
||||
database_app: Flask,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
service = MagicMock()
|
||||
service.get_average_app_interactions.return_value = [{"date": "2024-01-04", "interactions": 2.5}]
|
||||
monkeypatch.setattr(
|
||||
workflow_statistic_module,
|
||||
"application_services",
|
||||
lambda: SimpleNamespace(workflow_statistics=service),
|
||||
)
|
||||
self._patch_statistic_time_range(monkeypatch)
|
||||
|
||||
api = workflow_statistic_module.WorkflowAverageAppInteractionStatistic()
|
||||
method = unwrap(api.get)
|
||||
request_context = _make_request_context()
|
||||
|
||||
with database_app.test_request_context("/"):
|
||||
response = method(
|
||||
api,
|
||||
WorkflowStatisticQuery(),
|
||||
request_context,
|
||||
app_model=_make_app("app-1", tenant_id="t1"),
|
||||
)
|
||||
|
||||
assert response == {"data": [{"date": "2024-01-04", "interactions": 2.5}]}
|
||||
service.get_average_app_interactions.assert_called_once_with(
|
||||
request_context,
|
||||
app_id="app-1",
|
||||
start_date=None,
|
||||
end_date=None,
|
||||
timezone="UTC",
|
||||
)
|
||||
|
||||
def test_workflow_statistic_invalid_time_range(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
account = _make_account()
|
||||
account.timezone = "UTC"
|
||||
monkeypatch.setattr(
|
||||
workflow_statistic_module,
|
||||
"current_account_with_tenant",
|
||||
lambda: SimpleNamespace(account=account),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
repository,
|
||||
"get_daily_terminals_statistics",
|
||||
lambda **_kwargs: [{"date": "2024-01-02"}],
|
||||
workflow_statistic_module,
|
||||
"parse_time_range",
|
||||
MagicMock(side_effect=ValueError("invalid range")),
|
||||
)
|
||||
|
||||
with pytest.raises(BadRequest, match="invalid range"):
|
||||
workflow_statistic_module._resolve_statistic_time_range(WorkflowStatisticQuery())
|
||||
|
||||
@staticmethod
|
||||
def _patch_statistic_time_range(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
account = _make_account()
|
||||
account.timezone = "UTC"
|
||||
monkeypatch.setattr(
|
||||
workflow_statistic_module.DifyAPIRepositoryFactory,
|
||||
"create_api_workflow_run_repository",
|
||||
lambda *_args, **_kwargs: repository,
|
||||
workflow_statistic_module,
|
||||
"current_account_with_tenant",
|
||||
lambda: SimpleNamespace(account=account),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
workflow_statistic_module,
|
||||
@@ -739,16 +862,6 @@ class TestWorkflowStatisticEndpoints:
|
||||
lambda *_args, **_kwargs: (None, None),
|
||||
)
|
||||
|
||||
api = workflow_statistic_module.WorkflowDailyTerminalsStatistic()
|
||||
method = unwrap(api.get)
|
||||
|
||||
with database_app.test_request_context("/"):
|
||||
account = _make_account()
|
||||
account.timezone = "UTC"
|
||||
response = method(api, WorkflowStatisticQuery(), account, app_model=_make_app("app-1", tenant_id="t1"))
|
||||
|
||||
assert response.get_json() == {"data": [{"date": "2024-01-02"}]}
|
||||
|
||||
|
||||
class TestWorkflowTriggerEndpoints:
|
||||
def test_webhook_trigger_payload(self):
|
||||
|
||||
Reference in new issue
Block a user