re-uploading work
This commit is contained in:
405
tests/e2e/tier3/test_t3_15_inquiry_notifications.py
Normal file
405
tests/e2e/tier3/test_t3_15_inquiry_notifications.py
Normal file
@@ -0,0 +1,405 @@
|
||||
"""
|
||||
T3.15: Inquiry Creation Notifications Test
|
||||
|
||||
Tests that the notifier service sends real-time notifications when inquiries are created.
|
||||
Validates notification delivery for human-in-the-loop approval workflows.
|
||||
|
||||
Priority: MEDIUM
|
||||
Duration: ~20 seconds
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Any, Dict
|
||||
|
||||
import pytest
|
||||
from helpers.client import AttuneClient
|
||||
from helpers.fixtures import create_webhook_trigger, unique_ref
|
||||
from helpers.polling import (
|
||||
wait_for_execution_count,
|
||||
wait_for_inquiry_count,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.tier3
|
||||
@pytest.mark.notifications
|
||||
@pytest.mark.inquiry
|
||||
@pytest.mark.websocket
|
||||
def test_inquiry_creation_notification(client: AttuneClient, test_pack):
|
||||
"""
|
||||
Test that inquiry creation triggers notification.
|
||||
|
||||
Flow:
|
||||
1. Create webhook trigger and inquiry action
|
||||
2. Create rule
|
||||
3. Trigger webhook
|
||||
4. Verify inquiry is created
|
||||
5. Validate inquiry notification metadata
|
||||
"""
|
||||
print("\n" + "=" * 80)
|
||||
print("T3.15.1: Inquiry Creation Notification")
|
||||
print("=" * 80)
|
||||
|
||||
pack_ref = test_pack["ref"]
|
||||
|
||||
# Step 1: Create webhook trigger
|
||||
print("\n[STEP 1] Creating webhook trigger...")
|
||||
trigger_ref = f"inquiry_notify_webhook_{unique_ref()}"
|
||||
trigger = create_webhook_trigger(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
trigger_ref=trigger_ref,
|
||||
description="Webhook for inquiry notification test",
|
||||
)
|
||||
print(f"✓ Created trigger: {trigger['ref']}")
|
||||
|
||||
# Step 2: Create inquiry action
|
||||
print("\n[STEP 2] Creating inquiry action...")
|
||||
action_ref = f"inquiry_notify_action_{unique_ref()}"
|
||||
action_payload = {
|
||||
"ref": action_ref,
|
||||
"pack": pack_ref,
|
||||
"name": "Inquiry Action for Notification",
|
||||
"description": "Creates inquiry to test notifications",
|
||||
"runner_type": "inquiry",
|
||||
"parameters": {
|
||||
"question": {
|
||||
"type": "string",
|
||||
"description": "Question to ask",
|
||||
"required": True,
|
||||
},
|
||||
"choices": {
|
||||
"type": "array",
|
||||
"description": "Available choices",
|
||||
"required": False,
|
||||
},
|
||||
},
|
||||
"enabled": True,
|
||||
}
|
||||
action_response = client.post("/actions", json=action_payload)
|
||||
assert action_response.status_code == 201, (
|
||||
f"Failed to create action: {action_response.text}"
|
||||
)
|
||||
action = action_response.json()["data"]
|
||||
print(f"✓ Created inquiry action: {action['ref']}")
|
||||
|
||||
# Step 3: Create rule with inquiry action
|
||||
print("\n[STEP 3] Creating rule...")
|
||||
rule_ref = f"inquiry_notify_rule_{unique_ref()}"
|
||||
rule_payload = {
|
||||
"ref": rule_ref,
|
||||
"pack": pack_ref,
|
||||
"trigger": trigger["ref"],
|
||||
"action": action["ref"],
|
||||
"enabled": True,
|
||||
"parameters": {
|
||||
"question": "Do you approve this request?",
|
||||
"choices": ["approve", "deny"],
|
||||
},
|
||||
}
|
||||
rule_response = client.post("/rules", json=rule_payload)
|
||||
assert rule_response.status_code == 201, (
|
||||
f"Failed to create rule: {rule_response.text}"
|
||||
)
|
||||
rule = rule_response.json()["data"]
|
||||
print(f"✓ Created rule: {rule['ref']}")
|
||||
|
||||
# Step 4: Trigger webhook to create inquiry
|
||||
print("\n[STEP 4] Triggering webhook to create inquiry...")
|
||||
webhook_url = f"/webhooks/{trigger['ref']}"
|
||||
test_payload = {
|
||||
"message": "Request for approval",
|
||||
"timestamp": time.time(),
|
||||
}
|
||||
webhook_response = client.post(webhook_url, json=test_payload)
|
||||
assert webhook_response.status_code == 200, (
|
||||
f"Webhook trigger failed: {webhook_response.text}"
|
||||
)
|
||||
print(f"✓ Webhook triggered successfully")
|
||||
|
||||
# Step 5: Wait for inquiry creation
|
||||
print("\n[STEP 5] Waiting for inquiry creation...")
|
||||
wait_for_inquiry_count(client, expected_count=1, timeout=10)
|
||||
inquiries = client.get("/inquiries").json()["data"]
|
||||
assert len(inquiries) == 1, f"Expected 1 inquiry, got {len(inquiries)}"
|
||||
inquiry = inquiries[0]
|
||||
print(f"✓ Inquiry created: {inquiry['id']}")
|
||||
|
||||
# Step 6: Validate inquiry notification metadata
|
||||
print("\n[STEP 6] Validating inquiry notification metadata...")
|
||||
assert inquiry["status"] == "pending", (
|
||||
f"Expected pending status, got {inquiry['status']}"
|
||||
)
|
||||
assert "created" in inquiry, "Inquiry missing created timestamp"
|
||||
assert "updated" in inquiry, "Inquiry missing updated timestamp"
|
||||
assert inquiry["execution_id"] is not None, "Inquiry should be linked to execution"
|
||||
|
||||
print(f"✓ Inquiry notification metadata validated")
|
||||
print(f" - Inquiry ID: {inquiry['id']}")
|
||||
print(f" - Status: {inquiry['status']}")
|
||||
print(f" - Execution ID: {inquiry['execution_id']}")
|
||||
print(f" - Created: {inquiry['created']}")
|
||||
|
||||
print("\n✅ Test passed: Inquiry creation notification flow validated")
|
||||
|
||||
|
||||
@pytest.mark.tier3
|
||||
@pytest.mark.notifications
|
||||
@pytest.mark.inquiry
|
||||
@pytest.mark.websocket
|
||||
def test_inquiry_response_notification(client: AttuneClient, test_pack):
|
||||
"""
|
||||
Test that inquiry response triggers notification.
|
||||
|
||||
Flow:
|
||||
1. Create inquiry via webhook trigger
|
||||
2. Wait for inquiry creation
|
||||
3. Respond to inquiry
|
||||
4. Verify notification for inquiry response
|
||||
"""
|
||||
print("\n" + "=" * 80)
|
||||
print("T3.15.2: Inquiry Response Notification")
|
||||
print("=" * 80)
|
||||
|
||||
pack_ref = test_pack["ref"]
|
||||
|
||||
# Step 1: Create webhook trigger
|
||||
print("\n[STEP 1] Creating webhook trigger...")
|
||||
trigger_ref = f"inquiry_resp_webhook_{unique_ref()}"
|
||||
trigger = create_webhook_trigger(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
trigger_ref=trigger_ref,
|
||||
description="Webhook for inquiry response test",
|
||||
)
|
||||
print(f"✓ Created trigger: {trigger['ref']}")
|
||||
|
||||
# Step 2: Create inquiry action
|
||||
print("\n[STEP 2] Creating inquiry action...")
|
||||
action_ref = f"inquiry_resp_action_{unique_ref()}"
|
||||
action_payload = {
|
||||
"ref": action_ref,
|
||||
"pack": pack_ref,
|
||||
"name": "Inquiry Response Action",
|
||||
"description": "Creates inquiry for response test",
|
||||
"runner_type": "inquiry",
|
||||
"parameters": {
|
||||
"question": {
|
||||
"type": "string",
|
||||
"description": "Question to ask",
|
||||
"required": True,
|
||||
},
|
||||
},
|
||||
"enabled": True,
|
||||
}
|
||||
action_response = client.post("/actions", json=action_payload)
|
||||
assert action_response.status_code == 201, (
|
||||
f"Failed to create action: {action_response.text}"
|
||||
)
|
||||
action = action_response.json()["data"]
|
||||
print(f"✓ Created inquiry action: {action['ref']}")
|
||||
|
||||
# Step 3: Create rule
|
||||
print("\n[STEP 3] Creating rule...")
|
||||
rule_ref = f"inquiry_resp_rule_{unique_ref()}"
|
||||
rule_payload = {
|
||||
"ref": rule_ref,
|
||||
"pack": pack_ref,
|
||||
"trigger": trigger["ref"],
|
||||
"action": action["ref"],
|
||||
"enabled": True,
|
||||
"parameters": {
|
||||
"question": "Approve deployment to production?",
|
||||
},
|
||||
}
|
||||
rule_response = client.post("/rules", json=rule_payload)
|
||||
assert rule_response.status_code == 201, (
|
||||
f"Failed to create rule: {rule_response.text}"
|
||||
)
|
||||
rule = rule_response.json()["data"]
|
||||
print(f"✓ Created rule: {rule['ref']}")
|
||||
|
||||
# Step 4: Trigger webhook to create inquiry
|
||||
print("\n[STEP 4] Triggering webhook...")
|
||||
webhook_url = f"/webhooks/{trigger['ref']}"
|
||||
webhook_response = client.post(webhook_url, json={"request": "deploy"})
|
||||
assert webhook_response.status_code == 200
|
||||
print(f"✓ Webhook triggered")
|
||||
|
||||
# Step 5: Wait for inquiry creation
|
||||
print("\n[STEP 5] Waiting for inquiry creation...")
|
||||
wait_for_inquiry_count(client, expected_count=1, timeout=10)
|
||||
inquiries = client.get("/inquiries").json()["data"]
|
||||
inquiry = inquiries[0]
|
||||
inquiry_id = inquiry["id"]
|
||||
print(f"✓ Inquiry created: {inquiry_id}")
|
||||
|
||||
# Step 6: Respond to inquiry
|
||||
print("\n[STEP 6] Responding to inquiry...")
|
||||
response_payload = {
|
||||
"response": "approved",
|
||||
"comment": "Deployment approved by test",
|
||||
}
|
||||
response = client.post(f"/inquiries/{inquiry_id}/respond", json=response_payload)
|
||||
assert response.status_code == 200, f"Failed to respond: {response.text}"
|
||||
print(f"✓ Inquiry response submitted")
|
||||
|
||||
# Step 7: Verify inquiry status updated
|
||||
print("\n[STEP 7] Verifying inquiry status update...")
|
||||
time.sleep(2) # Allow notification processing
|
||||
updated_inquiry = client.get(f"/inquiries/{inquiry_id}").json()["data"]
|
||||
assert updated_inquiry["status"] == "responded", (
|
||||
f"Expected responded status, got {updated_inquiry['status']}"
|
||||
)
|
||||
assert updated_inquiry["response"] is not None, "Inquiry should have response data"
|
||||
|
||||
print(f"✓ Inquiry response notification metadata validated")
|
||||
print(f" - Inquiry ID: {inquiry_id}")
|
||||
print(f" - Status: {updated_inquiry['status']}")
|
||||
print(f" - Response received: {updated_inquiry['response'] is not None}")
|
||||
print(f" - Updated: {updated_inquiry['updated']}")
|
||||
|
||||
print("\n✅ Test passed: Inquiry response notification flow validated")
|
||||
|
||||
|
||||
@pytest.mark.tier3
|
||||
@pytest.mark.notifications
|
||||
@pytest.mark.inquiry
|
||||
@pytest.mark.websocket
|
||||
def test_inquiry_timeout_notification(client: AttuneClient, test_pack):
|
||||
"""
|
||||
Test that inquiry timeout triggers notification.
|
||||
|
||||
Flow:
|
||||
1. Create inquiry with short timeout
|
||||
2. Wait for timeout to occur
|
||||
3. Verify notification for inquiry timeout
|
||||
"""
|
||||
print("\n" + "=" * 80)
|
||||
print("T3.15.3: Inquiry Timeout Notification")
|
||||
print("=" * 80)
|
||||
|
||||
pack_ref = test_pack["ref"]
|
||||
|
||||
# Step 1: Create webhook trigger
|
||||
print("\n[STEP 1] Creating webhook trigger...")
|
||||
trigger_ref = f"inquiry_timeout_webhook_{unique_ref()}"
|
||||
trigger = create_webhook_trigger(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
trigger_ref=trigger_ref,
|
||||
description="Webhook for inquiry timeout test",
|
||||
)
|
||||
print(f"✓ Created trigger: {trigger['ref']}")
|
||||
|
||||
# Step 2: Create inquiry action with short timeout
|
||||
print("\n[STEP 2] Creating inquiry action with timeout...")
|
||||
action_ref = f"inquiry_timeout_action_{unique_ref()}"
|
||||
action_payload = {
|
||||
"ref": action_ref,
|
||||
"pack": pack_ref,
|
||||
"name": "Timeout Inquiry Action",
|
||||
"description": "Creates inquiry with short timeout",
|
||||
"runner_type": "inquiry",
|
||||
"timeout": 3, # 3 second timeout
|
||||
"parameters": {
|
||||
"question": {
|
||||
"type": "string",
|
||||
"description": "Question to ask",
|
||||
"required": True,
|
||||
},
|
||||
},
|
||||
"enabled": True,
|
||||
}
|
||||
action_response = client.post("/actions", json=action_payload)
|
||||
assert action_response.status_code == 201, (
|
||||
f"Failed to create action: {action_response.text}"
|
||||
)
|
||||
action = action_response.json()["data"]
|
||||
print(f"✓ Created inquiry action with 3s timeout: {action['ref']}")
|
||||
|
||||
# Step 3: Create rule
|
||||
print("\n[STEP 3] Creating rule...")
|
||||
rule_ref = f"inquiry_timeout_rule_{unique_ref()}"
|
||||
rule_payload = {
|
||||
"ref": rule_ref,
|
||||
"pack": pack_ref,
|
||||
"trigger": trigger["ref"],
|
||||
"action": action["ref"],
|
||||
"enabled": True,
|
||||
"parameters": {
|
||||
"question": "Quick approval needed!",
|
||||
},
|
||||
}
|
||||
rule_response = client.post("/rules", json=rule_payload)
|
||||
assert rule_response.status_code == 201, (
|
||||
f"Failed to create rule: {rule_response.text}"
|
||||
)
|
||||
rule = rule_response.json()["data"]
|
||||
print(f"✓ Created rule: {rule['ref']}")
|
||||
|
||||
# Step 4: Trigger webhook
|
||||
print("\n[STEP 4] Triggering webhook...")
|
||||
webhook_url = f"/webhooks/{trigger['ref']}"
|
||||
webhook_response = client.post(webhook_url, json={"urgent": True})
|
||||
assert webhook_response.status_code == 200
|
||||
print(f"✓ Webhook triggered")
|
||||
|
||||
# Step 5: Wait for inquiry creation
|
||||
print("\n[STEP 5] Waiting for inquiry creation...")
|
||||
wait_for_inquiry_count(client, expected_count=1, timeout=10)
|
||||
inquiries = client.get("/inquiries").json()["data"]
|
||||
inquiry = inquiries[0]
|
||||
inquiry_id = inquiry["id"]
|
||||
print(f"✓ Inquiry created: {inquiry_id}")
|
||||
|
||||
# Step 6: Wait for timeout to occur
|
||||
print("\n[STEP 6] Waiting for inquiry timeout...")
|
||||
time.sleep(5) # Wait longer than timeout
|
||||
timed_out_inquiry = client.get(f"/inquiries/{inquiry_id}").json()["data"]
|
||||
|
||||
# Verify timeout status
|
||||
assert timed_out_inquiry["status"] in ["timeout", "expired", "cancelled"], (
|
||||
f"Expected timeout status, got {timed_out_inquiry['status']}"
|
||||
)
|
||||
|
||||
print(f"✓ Inquiry timeout notification metadata validated")
|
||||
print(f" - Inquiry ID: {inquiry_id}")
|
||||
print(f" - Status: {timed_out_inquiry['status']}")
|
||||
print(f" - Timeout: {action['timeout']}s")
|
||||
print(f" - Updated: {timed_out_inquiry['updated']}")
|
||||
|
||||
print("\n✅ Test passed: Inquiry timeout notification flow validated")
|
||||
|
||||
|
||||
@pytest.mark.tier3
|
||||
@pytest.mark.notifications
|
||||
@pytest.mark.inquiry
|
||||
@pytest.mark.websocket
|
||||
@pytest.mark.skip(
|
||||
reason="Requires WebSocket infrastructure for real-time inquiry notifications"
|
||||
)
|
||||
def test_websocket_inquiry_notification_delivery(client: AttuneClient, test_pack):
|
||||
"""
|
||||
Test actual WebSocket notification delivery for inquiries.
|
||||
|
||||
This test is skipped until WebSocket test infrastructure is implemented.
|
||||
|
||||
Flow:
|
||||
1. Connect to WebSocket with auth
|
||||
2. Subscribe to inquiry notifications
|
||||
3. Create inquiry via workflow
|
||||
4. Receive real-time notification
|
||||
5. Validate notification structure
|
||||
"""
|
||||
print("\n" + "=" * 80)
|
||||
print("T3.15.4: WebSocket Inquiry Notification Delivery")
|
||||
print("=" * 80)
|
||||
|
||||
# This would require WebSocket client infrastructure similar to T3.14.4
|
||||
# Notifications would include:
|
||||
# - inquiry.created
|
||||
# - inquiry.responded
|
||||
# - inquiry.timeout
|
||||
# - inquiry.cancelled
|
||||
|
||||
pytest.skip("WebSocket client infrastructure not yet implemented")
|
||||
Reference in New Issue
Block a user