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):
|
def mock_external_dependencies(self):
|
||||||
"""Mock external service dependencies."""
|
"""Mock external service dependencies."""
|
||||||
with (
|
with (
|
||||||
patch("services.webhook_service.AsyncWorkflowService") as mock_async_service,
|
patch("services.trigger.webhook_service.AsyncWorkflowService") as mock_async_service,
|
||||||
patch("services.webhook_service.ToolFileManager") as mock_tool_file_manager,
|
patch("services.trigger.webhook_service.ToolFileManager") as mock_tool_file_manager,
|
||||||
patch("services.webhook_service.file_factory") as mock_file_factory,
|
patch("services.trigger.webhook_service.file_factory") as mock_file_factory,
|
||||||
patch("services.account_service.FeatureService") as mock_feature_service,
|
patch("services.account_service.FeatureService") as mock_feature_service,
|
||||||
):
|
):
|
||||||
# Mock ToolFileManager
|
# Mock ToolFileManager
|
||||||
|
|
@ -244,106 +244,166 @@ class TestWebhookService:
|
||||||
assert webhook_data["method"] == "POST"
|
assert webhook_data["method"] == "POST"
|
||||||
assert webhook_data["body"]["raw"] == "raw text content"
|
assert webhook_data["body"]["raw"] == "raw text content"
|
||||||
|
|
||||||
def test_validate_webhook_request_success(self):
|
def test_extract_and_validate_webhook_request_success(self):
|
||||||
"""Test successful webhook request validation."""
|
"""Test successful webhook request validation and type conversion."""
|
||||||
webhook_data = {
|
app = Flask(__name__)
|
||||||
"method": "POST",
|
|
||||||
"headers": {"Authorization": "Bearer token", "Content-Type": "application/json"},
|
|
||||||
"query_params": {"version": "1"},
|
|
||||||
"body": {"message": "hello"},
|
|
||||||
"files": {},
|
|
||||||
}
|
|
||||||
|
|
||||||
node_config = {
|
with app.test_request_context(
|
||||||
"data": {
|
"/webhook",
|
||||||
"method": "post",
|
method="POST",
|
||||||
"headers": [{"name": "Authorization", "required": True}, {"name": "Content-Type", "required": False}],
|
headers={"Content-Type": "application/json", "Authorization": "Bearer token"},
|
||||||
"params": [{"name": "version", "required": True}],
|
query_string="version=1",
|
||||||
"body": [{"name": "message", "type": "string", "required": True}],
|
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."""
|
"""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
|
def test_extract_and_validate_webhook_request_missing_required_header(self):
|
||||||
assert "HTTP method mismatch" in result["error"]
|
|
||||||
|
|
||||||
def test_validate_webhook_request_missing_required_header(self):
|
|
||||||
"""Test webhook validation with missing required header."""
|
"""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}]}}
|
with app.test_request_context(
|
||||||
|
"/webhook",
|
||||||
result = WebhookService.validate_webhook_request(webhook_data, node_config)
|
method="POST",
|
||||||
|
headers={"Content-Type": "application/json"},
|
||||||
assert result["valid"] is False
|
):
|
||||||
assert "Required header missing: Authorization" in result["error"]
|
webhook_trigger = MagicMock()
|
||||||
|
node_config = {
|
||||||
def test_validate_webhook_request_case_insensitive_headers(self):
|
"data": {
|
||||||
"""Test webhook validation with case-insensitive header matching."""
|
"method": "post",
|
||||||
webhook_data = {
|
"content_type": "application/json",
|
||||||
"method": "POST",
|
"headers": [{"name": "Authorization", "required": True}],
|
||||||
"headers": {"authorization": "Bearer token"}, # lowercase
|
}
|
||||||
"query_params": {},
|
|
||||||
"body": {},
|
|
||||||
"files": {},
|
|
||||||
}
|
|
||||||
|
|
||||||
node_config = {
|
|
||||||
"data": {
|
|
||||||
"method": "post",
|
|
||||||
"headers": [
|
|
||||||
{"name": "Authorization", "required": True} # Pascal case
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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."""
|
"""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
|
def test_extract_and_validate_webhook_request_missing_required_body_param(self):
|
||||||
assert "Required query parameter missing: version" in result["error"]
|
|
||||||
|
|
||||||
def test_validate_webhook_request_missing_required_body_param(self):
|
|
||||||
"""Test webhook validation with missing required body parameter."""
|
"""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
|
def test_extract_and_validate_webhook_request_missing_required_file(self):
|
||||||
assert "Required body parameter missing: message" in result["error"]
|
"""Test webhook validation when required file is missing from multipart request."""
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
def test_validate_webhook_request_missing_required_file(self):
|
with app.test_request_context(
|
||||||
"""Test webhook validation with missing required file parameter."""
|
"/webhook",
|
||||||
webhook_data = {"method": "POST", "headers": {}, "query_params": {}, "body": {}, "files": {}}
|
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["files"] == {}
|
||||||
|
|
||||||
assert result["valid"] is False
|
|
||||||
assert "Required file parameter missing: upload" in result["error"]
|
|
||||||
|
|
||||||
def test_trigger_workflow_execution_success(self, test_data, mock_external_dependencies, flask_app_with_containers):
|
def test_trigger_workflow_execution_success(self, test_data, mock_external_dependencies, flask_app_with_containers):
|
||||||
"""Test successful workflow execution trigger."""
|
"""Test successful workflow execution trigger."""
|
||||||
|
|
@ -357,12 +417,12 @@ class TestWebhookService:
|
||||||
|
|
||||||
with flask_app_with_containers.app_context():
|
with flask_app_with_containers.app_context():
|
||||||
# Mock tenant owner lookup to return the test account
|
# 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_query = MagicMock()
|
||||||
mock_select.return_value.join.return_value.where.return_value = mock_query
|
mock_select.return_value.join.return_value.where.return_value = mock_query
|
||||||
|
|
||||||
# Mock the session to return our test account
|
# 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_instance = MagicMock()
|
||||||
mock_session.return_value.__enter__.return_value = mock_session_instance
|
mock_session.return_value.__enter__.return_value = mock_session_instance
|
||||||
mock_session_instance.scalar.return_value = test_data["account"]
|
mock_session_instance.scalar.return_value = test_data["account"]
|
||||||
|
|
@ -384,8 +444,8 @@ class TestWebhookService:
|
||||||
with flask_app_with_containers.app_context():
|
with flask_app_with_containers.app_context():
|
||||||
# Mock tenant owner lookup to return None
|
# Mock tenant owner lookup to return None
|
||||||
with (
|
with (
|
||||||
patch("services.webhook_service.select") as mock_select,
|
patch("services.trigger.webhook_service.select") as mock_select,
|
||||||
patch("services.webhook_service.Session") as mock_session,
|
patch("services.trigger.webhook_service.Session") as mock_session,
|
||||||
):
|
):
|
||||||
mock_session_instance = MagicMock()
|
mock_session_instance = MagicMock()
|
||||||
mock_session.return_value.__enter__.return_value = mock_session_instance
|
mock_session.return_value.__enter__.return_value = mock_session_instance
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue