mirror of https://github.com/langgenius/dify.git
fix: webhook container tests
This commit is contained in:
parent
030da43ae3
commit
cbebac1d45
|
|
@ -20,9 +20,9 @@ class TestWebhookService:
|
|||
def mock_external_dependencies(self):
|
||||
"""Mock external service dependencies."""
|
||||
with (
|
||||
patch("services.webhook_service.AsyncWorkflowService") as mock_async_service,
|
||||
patch("services.webhook_service.ToolFileManager") as mock_tool_file_manager,
|
||||
patch("services.webhook_service.file_factory") as mock_file_factory,
|
||||
patch("services.trigger.webhook_service.AsyncWorkflowService") as mock_async_service,
|
||||
patch("services.trigger.webhook_service.ToolFileManager") as mock_tool_file_manager,
|
||||
patch("services.trigger.webhook_service.file_factory") as mock_file_factory,
|
||||
patch("services.account_service.FeatureService") as mock_feature_service,
|
||||
):
|
||||
# Mock ToolFileManager
|
||||
|
|
@ -244,106 +244,166 @@ class TestWebhookService:
|
|||
assert webhook_data["method"] == "POST"
|
||||
assert webhook_data["body"]["raw"] == "raw text content"
|
||||
|
||||
def test_validate_webhook_request_success(self):
|
||||
"""Test successful webhook request validation."""
|
||||
webhook_data = {
|
||||
"method": "POST",
|
||||
"headers": {"Authorization": "Bearer token", "Content-Type": "application/json"},
|
||||
"query_params": {"version": "1"},
|
||||
"body": {"message": "hello"},
|
||||
"files": {},
|
||||
}
|
||||
def test_extract_and_validate_webhook_request_success(self):
|
||||
"""Test successful webhook request validation and type conversion."""
|
||||
app = Flask(__name__)
|
||||
|
||||
node_config = {
|
||||
"data": {
|
||||
"method": "post",
|
||||
"headers": [{"name": "Authorization", "required": True}, {"name": "Content-Type", "required": False}],
|
||||
"params": [{"name": "version", "required": True}],
|
||||
"body": [{"name": "message", "type": "string", "required": True}],
|
||||
with app.test_request_context(
|
||||
"/webhook",
|
||||
method="POST",
|
||||
headers={"Content-Type": "application/json", "Authorization": "Bearer token"},
|
||||
query_string="version=1",
|
||||
json={"message": "hello"},
|
||||
):
|
||||
webhook_trigger = MagicMock()
|
||||
node_config = {
|
||||
"data": {
|
||||
"method": "post",
|
||||
"content_type": "application/json",
|
||||
"headers": [
|
||||
{"name": "Authorization", "required": True},
|
||||
{"name": "Content-Type", "required": False},
|
||||
],
|
||||
"params": [{"name": "version", "required": True}],
|
||||
"body": [{"name": "message", "type": "string", "required": True}],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = WebhookService.validate_webhook_request(webhook_data, node_config)
|
||||
result = WebhookService.extract_and_validate_webhook_data(webhook_trigger, node_config)
|
||||
|
||||
assert result["valid"] is True
|
||||
assert result["headers"]["Authorization"] == "Bearer token"
|
||||
assert result["query_params"]["version"] == "1"
|
||||
assert result["body"]["message"] == "hello"
|
||||
|
||||
def test_validate_webhook_request_method_mismatch(self):
|
||||
def test_extract_and_validate_webhook_request_method_mismatch(self):
|
||||
"""Test webhook validation with HTTP method mismatch."""
|
||||
webhook_data = {"method": "GET", "headers": {}, "query_params": {}, "body": {}, "files": {}}
|
||||
app = Flask(__name__)
|
||||
|
||||
node_config = {"data": {"method": "post"}}
|
||||
with app.test_request_context(
|
||||
"/webhook",
|
||||
method="GET",
|
||||
headers={"Content-Type": "application/json"},
|
||||
):
|
||||
webhook_trigger = MagicMock()
|
||||
node_config = {"data": {"method": "post", "content_type": "application/json"}}
|
||||
|
||||
result = WebhookService.validate_webhook_request(webhook_data, node_config)
|
||||
with pytest.raises(ValueError, match="HTTP method mismatch"):
|
||||
WebhookService.extract_and_validate_webhook_data(webhook_trigger, node_config)
|
||||
|
||||
assert result["valid"] is False
|
||||
assert "HTTP method mismatch" in result["error"]
|
||||
|
||||
def test_validate_webhook_request_missing_required_header(self):
|
||||
def test_extract_and_validate_webhook_request_missing_required_header(self):
|
||||
"""Test webhook validation with missing required header."""
|
||||
webhook_data = {"method": "POST", "headers": {}, "query_params": {}, "body": {}, "files": {}}
|
||||
app = Flask(__name__)
|
||||
|
||||
node_config = {"data": {"method": "post", "headers": [{"name": "Authorization", "required": True}]}}
|
||||
|
||||
result = WebhookService.validate_webhook_request(webhook_data, node_config)
|
||||
|
||||
assert result["valid"] is False
|
||||
assert "Required header missing: Authorization" in result["error"]
|
||||
|
||||
def test_validate_webhook_request_case_insensitive_headers(self):
|
||||
"""Test webhook validation with case-insensitive header matching."""
|
||||
webhook_data = {
|
||||
"method": "POST",
|
||||
"headers": {"authorization": "Bearer token"}, # lowercase
|
||||
"query_params": {},
|
||||
"body": {},
|
||||
"files": {},
|
||||
}
|
||||
|
||||
node_config = {
|
||||
"data": {
|
||||
"method": "post",
|
||||
"headers": [
|
||||
{"name": "Authorization", "required": True} # Pascal case
|
||||
],
|
||||
with app.test_request_context(
|
||||
"/webhook",
|
||||
method="POST",
|
||||
headers={"Content-Type": "application/json"},
|
||||
):
|
||||
webhook_trigger = MagicMock()
|
||||
node_config = {
|
||||
"data": {
|
||||
"method": "post",
|
||||
"content_type": "application/json",
|
||||
"headers": [{"name": "Authorization", "required": True}],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = WebhookService.validate_webhook_request(webhook_data, node_config)
|
||||
with pytest.raises(ValueError, match="Required header missing: Authorization"):
|
||||
WebhookService.extract_and_validate_webhook_data(webhook_trigger, node_config)
|
||||
|
||||
assert result["valid"] is True
|
||||
def test_extract_and_validate_webhook_request_case_insensitive_headers(self):
|
||||
"""Test webhook validation with case-insensitive header matching."""
|
||||
app = Flask(__name__)
|
||||
|
||||
def test_validate_webhook_request_missing_required_param(self):
|
||||
with app.test_request_context(
|
||||
"/webhook",
|
||||
method="POST",
|
||||
headers={"Content-Type": "application/json", "authorization": "Bearer token"},
|
||||
json={"message": "hello"},
|
||||
):
|
||||
webhook_trigger = MagicMock()
|
||||
node_config = {
|
||||
"data": {
|
||||
"method": "post",
|
||||
"content_type": "application/json",
|
||||
"headers": [{"name": "Authorization", "required": True}],
|
||||
"body": [{"name": "message", "type": "string", "required": True}],
|
||||
}
|
||||
}
|
||||
|
||||
result = WebhookService.extract_and_validate_webhook_data(webhook_trigger, node_config)
|
||||
|
||||
assert result["headers"].get("Authorization") == "Bearer token"
|
||||
|
||||
def test_extract_and_validate_webhook_request_missing_required_param(self):
|
||||
"""Test webhook validation with missing required query parameter."""
|
||||
webhook_data = {"method": "POST", "headers": {}, "query_params": {}, "body": {}, "files": {}}
|
||||
app = Flask(__name__)
|
||||
|
||||
node_config = {"data": {"method": "post", "params": [{"name": "version", "required": True}]}}
|
||||
with app.test_request_context(
|
||||
"/webhook",
|
||||
method="POST",
|
||||
headers={"Content-Type": "application/json"},
|
||||
json={"message": "hello"},
|
||||
):
|
||||
webhook_trigger = MagicMock()
|
||||
node_config = {
|
||||
"data": {
|
||||
"method": "post",
|
||||
"content_type": "application/json",
|
||||
"params": [{"name": "version", "required": True}],
|
||||
"body": [{"name": "message", "type": "string", "required": True}],
|
||||
}
|
||||
}
|
||||
|
||||
result = WebhookService.validate_webhook_request(webhook_data, node_config)
|
||||
with pytest.raises(ValueError, match="Required parameter missing: version"):
|
||||
WebhookService.extract_and_validate_webhook_data(webhook_trigger, node_config)
|
||||
|
||||
assert result["valid"] is False
|
||||
assert "Required query parameter missing: version" in result["error"]
|
||||
|
||||
def test_validate_webhook_request_missing_required_body_param(self):
|
||||
def test_extract_and_validate_webhook_request_missing_required_body_param(self):
|
||||
"""Test webhook validation with missing required body parameter."""
|
||||
webhook_data = {"method": "POST", "headers": {}, "query_params": {}, "body": {}, "files": {}}
|
||||
app = Flask(__name__)
|
||||
|
||||
node_config = {"data": {"method": "post", "body": [{"name": "message", "type": "string", "required": True}]}}
|
||||
with app.test_request_context(
|
||||
"/webhook",
|
||||
method="POST",
|
||||
headers={"Content-Type": "application/json"},
|
||||
json={},
|
||||
):
|
||||
webhook_trigger = MagicMock()
|
||||
node_config = {
|
||||
"data": {
|
||||
"method": "post",
|
||||
"content_type": "application/json",
|
||||
"body": [{"name": "message", "type": "string", "required": True}],
|
||||
}
|
||||
}
|
||||
|
||||
result = WebhookService.validate_webhook_request(webhook_data, node_config)
|
||||
with pytest.raises(ValueError, match="Required body parameter missing: message"):
|
||||
WebhookService.extract_and_validate_webhook_data(webhook_trigger, node_config)
|
||||
|
||||
assert result["valid"] is False
|
||||
assert "Required body parameter missing: message" in result["error"]
|
||||
def test_extract_and_validate_webhook_request_missing_required_file(self):
|
||||
"""Test webhook validation when required file is missing from multipart request."""
|
||||
app = Flask(__name__)
|
||||
|
||||
def test_validate_webhook_request_missing_required_file(self):
|
||||
"""Test webhook validation with missing required file parameter."""
|
||||
webhook_data = {"method": "POST", "headers": {}, "query_params": {}, "body": {}, "files": {}}
|
||||
with app.test_request_context(
|
||||
"/webhook",
|
||||
method="POST",
|
||||
data={"note": "test"},
|
||||
content_type="multipart/form-data",
|
||||
):
|
||||
webhook_trigger = MagicMock()
|
||||
webhook_trigger.tenant_id = "tenant"
|
||||
webhook_trigger.created_by = "user"
|
||||
node_config = {
|
||||
"data": {
|
||||
"method": "post",
|
||||
"content_type": "multipart/form-data",
|
||||
"body": [{"name": "upload", "type": "file", "required": True}],
|
||||
}
|
||||
}
|
||||
|
||||
node_config = {"data": {"method": "post", "body": [{"name": "upload", "type": "file", "required": True}]}}
|
||||
result = WebhookService.extract_and_validate_webhook_data(webhook_trigger, node_config)
|
||||
|
||||
result = WebhookService.validate_webhook_request(webhook_data, node_config)
|
||||
|
||||
assert result["valid"] is False
|
||||
assert "Required file parameter missing: upload" in result["error"]
|
||||
assert result["files"] == {}
|
||||
|
||||
def test_trigger_workflow_execution_success(self, test_data, mock_external_dependencies, flask_app_with_containers):
|
||||
"""Test successful workflow execution trigger."""
|
||||
|
|
@ -357,12 +417,12 @@ class TestWebhookService:
|
|||
|
||||
with flask_app_with_containers.app_context():
|
||||
# Mock tenant owner lookup to return the test account
|
||||
with patch("services.webhook_service.select") as mock_select:
|
||||
with patch("services.trigger.webhook_service.select") as mock_select:
|
||||
mock_query = MagicMock()
|
||||
mock_select.return_value.join.return_value.where.return_value = mock_query
|
||||
|
||||
# Mock the session to return our test account
|
||||
with patch("services.webhook_service.Session") as mock_session:
|
||||
with patch("services.trigger.webhook_service.Session") as mock_session:
|
||||
mock_session_instance = MagicMock()
|
||||
mock_session.return_value.__enter__.return_value = mock_session_instance
|
||||
mock_session_instance.scalar.return_value = test_data["account"]
|
||||
|
|
@ -384,8 +444,8 @@ class TestWebhookService:
|
|||
with flask_app_with_containers.app_context():
|
||||
# Mock tenant owner lookup to return None
|
||||
with (
|
||||
patch("services.webhook_service.select") as mock_select,
|
||||
patch("services.webhook_service.Session") as mock_session,
|
||||
patch("services.trigger.webhook_service.select") as mock_select,
|
||||
patch("services.trigger.webhook_service.Session") as mock_session,
|
||||
):
|
||||
mock_session_instance = MagicMock()
|
||||
mock_session.return_value.__enter__.return_value = mock_session_instance
|
||||
|
|
|
|||
Loading…
Reference in New Issue