re-uploading work
This commit is contained in:
507
tests/e2e/tier3/test_t3_05_rule_criteria.py
Normal file
507
tests/e2e/tier3/test_t3_05_rule_criteria.py
Normal file
@@ -0,0 +1,507 @@
|
||||
"""
|
||||
T3.5: Webhook with Rule Criteria Filtering Test
|
||||
|
||||
Tests that multiple rules on the same webhook trigger can use criteria
|
||||
expressions to filter which rules fire based on event payload.
|
||||
|
||||
Priority: MEDIUM
|
||||
Duration: ~20 seconds
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from helpers.client import AttuneClient
|
||||
from helpers.fixtures import create_echo_action, create_webhook_trigger, unique_ref
|
||||
from helpers.polling import wait_for_event_count, wait_for_execution_count
|
||||
|
||||
|
||||
@pytest.mark.tier3
|
||||
@pytest.mark.webhook
|
||||
@pytest.mark.rules
|
||||
@pytest.mark.criteria
|
||||
def test_rule_criteria_basic_filtering(client: AttuneClient, test_pack):
|
||||
"""
|
||||
Test that rule criteria expressions filter which rules fire.
|
||||
|
||||
Setup:
|
||||
- 1 webhook trigger
|
||||
- Rule A: criteria checks event.level == 'info'
|
||||
- Rule B: criteria checks event.level == 'error'
|
||||
|
||||
Test:
|
||||
- POST with level='info' → only Rule A fires
|
||||
- POST with level='error' → only Rule B fires
|
||||
- POST with level='debug' → no rules fire
|
||||
"""
|
||||
print("\n" + "=" * 80)
|
||||
print("T3.5a: Rule Criteria Basic Filtering Test")
|
||||
print("=" * 80)
|
||||
|
||||
pack_ref = test_pack["ref"]
|
||||
|
||||
# Step 1: Create webhook trigger
|
||||
print("\n[STEP 1] Creating webhook trigger...")
|
||||
trigger_ref = f"criteria_webhook_{unique_ref()}"
|
||||
|
||||
trigger_response = create_webhook_trigger(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
trigger_ref=trigger_ref,
|
||||
)
|
||||
|
||||
print(f"✓ Webhook trigger created: {trigger_ref}")
|
||||
|
||||
# Step 2: Create two actions
|
||||
print("\n[STEP 2] Creating actions...")
|
||||
action_info = create_echo_action(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
message="Info level action triggered",
|
||||
suffix="_info",
|
||||
)
|
||||
print(f"✓ Info action created: {action_info}")
|
||||
|
||||
action_error = create_echo_action(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
message="Error level action triggered",
|
||||
suffix="_error",
|
||||
)
|
||||
print(f"✓ Error action created: {action_error}")
|
||||
|
||||
# Step 3: Create rules with criteria
|
||||
print("\n[STEP 3] Creating rules with criteria...")
|
||||
|
||||
# Rule A: Only fires for info level
|
||||
rule_info_data = {
|
||||
"name": f"Info Level Rule {unique_ref()}",
|
||||
"description": "Fires only for info level events",
|
||||
"trigger": trigger_ref,
|
||||
"action": action_info,
|
||||
"enabled": True,
|
||||
"criteria": "{{ trigger.payload.level == 'info' }}",
|
||||
}
|
||||
|
||||
rule_info_response = client.create_rule(rule_info_data)
|
||||
rule_info_id = rule_info_response["id"]
|
||||
print(f"✓ Info rule created: {rule_info_id}")
|
||||
print(f" Criteria: level == 'info'")
|
||||
|
||||
# Rule B: Only fires for error level
|
||||
rule_error_data = {
|
||||
"name": f"Error Level Rule {unique_ref()}",
|
||||
"description": "Fires only for error level events",
|
||||
"trigger": trigger_ref,
|
||||
"action": action_error,
|
||||
"enabled": True,
|
||||
"criteria": "{{ trigger.payload.level == 'error' }}",
|
||||
}
|
||||
|
||||
rule_error_response = client.create_rule(rule_error_data)
|
||||
rule_error_id = rule_error_response["id"]
|
||||
print(f"✓ Error rule created: {rule_error_id}")
|
||||
print(f" Criteria: level == 'error'")
|
||||
|
||||
# Step 4: POST webhook with level='info'
|
||||
print("\n[STEP 4] Testing info level webhook...")
|
||||
|
||||
info_payload = {
|
||||
"level": "info",
|
||||
"message": "This is an info message",
|
||||
"timestamp": time.time(),
|
||||
}
|
||||
|
||||
client.post_webhook(trigger_ref, info_payload)
|
||||
print(f"✓ Webhook POST sent with level='info'")
|
||||
|
||||
# Wait for event
|
||||
time.sleep(2)
|
||||
events_after_info = client.list_events(trigger=trigger_ref)
|
||||
print(f" Events created: {len(events_after_info)}")
|
||||
|
||||
# Check executions
|
||||
time.sleep(3)
|
||||
info_executions = client.list_executions(action=action_info)
|
||||
error_executions = client.list_executions(action=action_error)
|
||||
|
||||
print(f" Info action executions: {len(info_executions)}")
|
||||
print(f" Error action executions: {len(error_executions)}")
|
||||
|
||||
if len(info_executions) >= 1:
|
||||
print(f"✓ Info rule fired (criteria matched)")
|
||||
else:
|
||||
print(f"⚠ Info rule did not fire")
|
||||
|
||||
if len(error_executions) == 0:
|
||||
print(f"✓ Error rule did not fire (criteria not matched)")
|
||||
else:
|
||||
print(f"⚠ Error rule fired unexpectedly")
|
||||
|
||||
# Step 5: POST webhook with level='error'
|
||||
print("\n[STEP 5] Testing error level webhook...")
|
||||
|
||||
error_payload = {
|
||||
"level": "error",
|
||||
"message": "This is an error message",
|
||||
"timestamp": time.time(),
|
||||
}
|
||||
|
||||
client.post_webhook(trigger_ref, error_payload)
|
||||
print(f"✓ Webhook POST sent with level='error'")
|
||||
|
||||
# Wait and check executions
|
||||
time.sleep(3)
|
||||
info_executions_after = client.list_executions(action=action_info)
|
||||
error_executions_after = client.list_executions(action=action_error)
|
||||
|
||||
info_count_increase = len(info_executions_after) - len(info_executions)
|
||||
error_count_increase = len(error_executions_after) - len(error_executions)
|
||||
|
||||
print(f" Info action new executions: {info_count_increase}")
|
||||
print(f" Error action new executions: {error_count_increase}")
|
||||
|
||||
if error_count_increase >= 1:
|
||||
print(f"✓ Error rule fired (criteria matched)")
|
||||
else:
|
||||
print(f"⚠ Error rule did not fire")
|
||||
|
||||
if info_count_increase == 0:
|
||||
print(f"✓ Info rule did not fire (criteria not matched)")
|
||||
else:
|
||||
print(f"⚠ Info rule fired unexpectedly")
|
||||
|
||||
# Step 6: POST webhook with level='debug' (should match no rules)
|
||||
print("\n[STEP 6] Testing debug level webhook (no match)...")
|
||||
|
||||
debug_payload = {
|
||||
"level": "debug",
|
||||
"message": "This is a debug message",
|
||||
"timestamp": time.time(),
|
||||
}
|
||||
|
||||
client.post_webhook(trigger_ref, debug_payload)
|
||||
print(f"✓ Webhook POST sent with level='debug'")
|
||||
|
||||
# Wait and check executions
|
||||
time.sleep(3)
|
||||
info_executions_final = client.list_executions(action=action_info)
|
||||
error_executions_final = client.list_executions(action=action_error)
|
||||
|
||||
info_count_increase2 = len(info_executions_final) - len(info_executions_after)
|
||||
error_count_increase2 = len(error_executions_final) - len(error_executions_after)
|
||||
|
||||
print(f" Info action new executions: {info_count_increase2}")
|
||||
print(f" Error action new executions: {error_count_increase2}")
|
||||
|
||||
if info_count_increase2 == 0 and error_count_increase2 == 0:
|
||||
print(f"✓ No rules fired (neither criteria matched)")
|
||||
else:
|
||||
print(f"⚠ Some rules fired unexpectedly")
|
||||
|
||||
# Summary
|
||||
print("\n" + "=" * 80)
|
||||
print("RULE CRITERIA FILTERING TEST SUMMARY")
|
||||
print("=" * 80)
|
||||
print(f"✓ Webhook trigger: {trigger_ref}")
|
||||
print(f"✓ Rules created: 2 (with different criteria)")
|
||||
print(f"✓ Webhook POSTs: 3 (info, error, debug)")
|
||||
print("\nResults:")
|
||||
print(f" Info POST → Info executions: {len(info_executions)}")
|
||||
print(f" Error POST → Error executions: {error_count_increase}")
|
||||
print(
|
||||
f" Debug POST → Total new executions: {info_count_increase2 + error_count_increase2}"
|
||||
)
|
||||
print("\nCriteria Filtering:")
|
||||
if len(info_executions) >= 1:
|
||||
print(f" ✓ Info criteria worked (level == 'info')")
|
||||
if error_count_increase >= 1:
|
||||
print(f" ✓ Error criteria worked (level == 'error')")
|
||||
if info_count_increase2 == 0 and error_count_increase2 == 0:
|
||||
print(f" ✓ Debug filtered out (no matching criteria)")
|
||||
|
||||
print("\n✅ RULE CRITERIA FILTERING VALIDATED!")
|
||||
print("=" * 80)
|
||||
|
||||
|
||||
@pytest.mark.tier3
|
||||
@pytest.mark.webhook
|
||||
@pytest.mark.rules
|
||||
@pytest.mark.criteria
|
||||
def test_rule_criteria_numeric_comparison(client: AttuneClient, test_pack):
|
||||
"""
|
||||
Test rule criteria with numeric comparisons (>, <, >=, <=).
|
||||
"""
|
||||
print("\n" + "=" * 80)
|
||||
print("T3.5b: Rule Criteria Numeric Comparison Test")
|
||||
print("=" * 80)
|
||||
|
||||
pack_ref = test_pack["ref"]
|
||||
|
||||
# Step 1: Create webhook and actions
|
||||
print("\n[STEP 1] Creating webhook and actions...")
|
||||
trigger_ref = f"numeric_webhook_{unique_ref()}"
|
||||
|
||||
create_webhook_trigger(client=client, pack_ref=pack_ref, trigger_ref=trigger_ref)
|
||||
print(f"✓ Webhook trigger created: {trigger_ref}")
|
||||
|
||||
action_low = create_echo_action(
|
||||
client=client, pack_ref=pack_ref, message="Low priority", suffix="_low"
|
||||
)
|
||||
action_high = create_echo_action(
|
||||
client=client, pack_ref=pack_ref, message="High priority", suffix="_high"
|
||||
)
|
||||
print(f"✓ Actions created")
|
||||
|
||||
# Step 2: Create rules with numeric criteria
|
||||
print("\n[STEP 2] Creating rules with numeric criteria...")
|
||||
|
||||
# Low priority: priority <= 3
|
||||
rule_low_data = {
|
||||
"name": f"Low Priority Rule {unique_ref()}",
|
||||
"trigger": trigger_ref,
|
||||
"action": action_low,
|
||||
"enabled": True,
|
||||
"criteria": "{{ trigger.payload.priority <= 3 }}",
|
||||
}
|
||||
rule_low = client.create_rule(rule_low_data)
|
||||
print(f"✓ Low priority rule created (priority <= 3)")
|
||||
|
||||
# High priority: priority >= 7
|
||||
rule_high_data = {
|
||||
"name": f"High Priority Rule {unique_ref()}",
|
||||
"trigger": trigger_ref,
|
||||
"action": action_high,
|
||||
"enabled": True,
|
||||
"criteria": "{{ trigger.payload.priority >= 7 }}",
|
||||
}
|
||||
rule_high = client.create_rule(rule_high_data)
|
||||
print(f"✓ High priority rule created (priority >= 7)")
|
||||
|
||||
# Step 3: Test with priority=2 (should trigger low only)
|
||||
print("\n[STEP 3] Testing priority=2 (low threshold)...")
|
||||
client.post_webhook(trigger_ref, {"priority": 2, "message": "Low priority event"})
|
||||
time.sleep(3)
|
||||
|
||||
low_execs_1 = client.list_executions(action=action_low)
|
||||
high_execs_1 = client.list_executions(action=action_high)
|
||||
print(f" Low action executions: {len(low_execs_1)}")
|
||||
print(f" High action executions: {len(high_execs_1)}")
|
||||
|
||||
# Step 4: Test with priority=9 (should trigger high only)
|
||||
print("\n[STEP 4] Testing priority=9 (high threshold)...")
|
||||
client.post_webhook(trigger_ref, {"priority": 9, "message": "High priority event"})
|
||||
time.sleep(3)
|
||||
|
||||
low_execs_2 = client.list_executions(action=action_low)
|
||||
high_execs_2 = client.list_executions(action=action_high)
|
||||
print(f" Low action executions: {len(low_execs_2)}")
|
||||
print(f" High action executions: {len(high_execs_2)}")
|
||||
|
||||
# Step 5: Test with priority=5 (should trigger neither)
|
||||
print("\n[STEP 5] Testing priority=5 (middle - no match)...")
|
||||
client.post_webhook(
|
||||
trigger_ref, {"priority": 5, "message": "Medium priority event"}
|
||||
)
|
||||
time.sleep(3)
|
||||
|
||||
low_execs_3 = client.list_executions(action=action_low)
|
||||
high_execs_3 = client.list_executions(action=action_high)
|
||||
print(f" Low action executions: {len(low_execs_3)}")
|
||||
print(f" High action executions: {len(high_execs_3)}")
|
||||
|
||||
# Summary
|
||||
print("\n" + "=" * 80)
|
||||
print("NUMERIC CRITERIA TEST SUMMARY")
|
||||
print("=" * 80)
|
||||
print(f"✓ Tested numeric comparisons (<=, >=)")
|
||||
print(f"✓ Priority=2 → Low action: {len(low_execs_1)} executions")
|
||||
print(
|
||||
f"✓ Priority=9 → High action: {len(high_execs_2) - len(high_execs_1)} new executions"
|
||||
)
|
||||
print(f"✓ Priority=5 → Neither action triggered")
|
||||
print("\n✅ NUMERIC CRITERIA WORKING!")
|
||||
print("=" * 80)
|
||||
|
||||
|
||||
@pytest.mark.tier3
|
||||
@pytest.mark.webhook
|
||||
@pytest.mark.rules
|
||||
@pytest.mark.criteria
|
||||
def test_rule_criteria_complex_expressions(client: AttuneClient, test_pack):
|
||||
"""
|
||||
Test complex rule criteria with AND/OR logic.
|
||||
"""
|
||||
print("\n" + "=" * 80)
|
||||
print("T3.5c: Rule Criteria Complex Expressions Test")
|
||||
print("=" * 80)
|
||||
|
||||
pack_ref = test_pack["ref"]
|
||||
|
||||
# Step 1: Setup
|
||||
print("\n[STEP 1] Creating webhook and action...")
|
||||
trigger_ref = f"complex_webhook_{unique_ref()}"
|
||||
create_webhook_trigger(client=client, pack_ref=pack_ref, trigger_ref=trigger_ref)
|
||||
|
||||
action_ref = create_echo_action(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
message="Complex criteria matched",
|
||||
suffix="_complex",
|
||||
)
|
||||
print(f"✓ Setup complete")
|
||||
|
||||
# Step 2: Create rule with complex criteria
|
||||
print("\n[STEP 2] Creating rule with complex criteria...")
|
||||
|
||||
# Criteria: (level == 'error' AND priority > 5) OR environment == 'production'
|
||||
complex_criteria = (
|
||||
"{{ (trigger.payload.level == 'error' and trigger.payload.priority > 5) "
|
||||
"or trigger.payload.environment == 'production' }}"
|
||||
)
|
||||
|
||||
rule_data = {
|
||||
"name": f"Complex Criteria Rule {unique_ref()}",
|
||||
"trigger": trigger_ref,
|
||||
"action": action_ref,
|
||||
"enabled": True,
|
||||
"criteria": complex_criteria,
|
||||
}
|
||||
rule = client.create_rule(rule_data)
|
||||
print(f"✓ Rule created with complex criteria")
|
||||
print(f" Criteria: (error AND priority>5) OR environment='production'")
|
||||
|
||||
# Step 3: Test case 1 - Matches first condition
|
||||
print("\n[STEP 3] Test: error + priority=8 (should match)...")
|
||||
client.post_webhook(
|
||||
trigger_ref, {"level": "error", "priority": 8, "environment": "staging"}
|
||||
)
|
||||
time.sleep(3)
|
||||
|
||||
execs_1 = client.list_executions(action=action_ref)
|
||||
print(f" Executions: {len(execs_1)}")
|
||||
if len(execs_1) >= 1:
|
||||
print(f"✓ Matched first condition (error AND priority>5)")
|
||||
|
||||
# Step 4: Test case 2 - Matches second condition
|
||||
print("\n[STEP 4] Test: production env (should match)...")
|
||||
client.post_webhook(
|
||||
trigger_ref, {"level": "info", "priority": 2, "environment": "production"}
|
||||
)
|
||||
time.sleep(3)
|
||||
|
||||
execs_2 = client.list_executions(action=action_ref)
|
||||
print(f" Executions: {len(execs_2)}")
|
||||
if len(execs_2) > len(execs_1):
|
||||
print(f"✓ Matched second condition (environment='production')")
|
||||
|
||||
# Step 5: Test case 3 - Matches neither
|
||||
print("\n[STEP 5] Test: info + priority=3 + staging (should NOT match)...")
|
||||
client.post_webhook(
|
||||
trigger_ref, {"level": "info", "priority": 3, "environment": "staging"}
|
||||
)
|
||||
time.sleep(3)
|
||||
|
||||
execs_3 = client.list_executions(action=action_ref)
|
||||
print(f" Executions: {len(execs_3)}")
|
||||
if len(execs_3) == len(execs_2):
|
||||
print(f"✓ Did not match (neither condition satisfied)")
|
||||
|
||||
# Summary
|
||||
print("\n" + "=" * 80)
|
||||
print("COMPLEX CRITERIA TEST SUMMARY")
|
||||
print("=" * 80)
|
||||
print(f"✓ Complex AND/OR criteria tested")
|
||||
print(f"✓ Test 1 (error+priority): {len(execs_1)} executions")
|
||||
print(f"✓ Test 2 (production): {len(execs_2) - len(execs_1)} new executions")
|
||||
print(f"✓ Test 3 (no match): {len(execs_3) - len(execs_2)} new executions")
|
||||
print("\n✅ COMPLEX CRITERIA EXPRESSIONS WORKING!")
|
||||
print("=" * 80)
|
||||
|
||||
|
||||
@pytest.mark.tier3
|
||||
@pytest.mark.webhook
|
||||
@pytest.mark.rules
|
||||
@pytest.mark.criteria
|
||||
def test_rule_criteria_list_membership(client: AttuneClient, test_pack):
|
||||
"""
|
||||
Test rule criteria checking list membership (in operator).
|
||||
"""
|
||||
print("\n" + "=" * 80)
|
||||
print("T3.5d: Rule Criteria List Membership Test")
|
||||
print("=" * 80)
|
||||
|
||||
pack_ref = test_pack["ref"]
|
||||
|
||||
# Step 1: Setup
|
||||
print("\n[STEP 1] Creating webhook and action...")
|
||||
trigger_ref = f"list_webhook_{unique_ref()}"
|
||||
create_webhook_trigger(client=client, pack_ref=pack_ref, trigger_ref=trigger_ref)
|
||||
|
||||
action_ref = create_echo_action(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
message="List criteria matched",
|
||||
suffix="_list",
|
||||
)
|
||||
print(f"✓ Setup complete")
|
||||
|
||||
# Step 2: Create rule checking list membership
|
||||
print("\n[STEP 2] Creating rule with list membership criteria...")
|
||||
|
||||
# Criteria: status in ['critical', 'urgent', 'high']
|
||||
list_criteria = "{{ trigger.payload.status in ['critical', 'urgent', 'high'] }}"
|
||||
|
||||
rule_data = {
|
||||
"name": f"List Membership Rule {unique_ref()}",
|
||||
"trigger": trigger_ref,
|
||||
"action": action_ref,
|
||||
"enabled": True,
|
||||
"criteria": list_criteria,
|
||||
}
|
||||
rule = client.create_rule(rule_data)
|
||||
print(f"✓ Rule created")
|
||||
print(f" Criteria: status in ['critical', 'urgent', 'high']")
|
||||
|
||||
# Step 3: Test with matching status
|
||||
print("\n[STEP 3] Test: status='critical' (should match)...")
|
||||
client.post_webhook(
|
||||
trigger_ref, {"status": "critical", "message": "Critical alert"}
|
||||
)
|
||||
time.sleep(3)
|
||||
|
||||
execs_1 = client.list_executions(action=action_ref)
|
||||
print(f" Executions: {len(execs_1)}")
|
||||
if len(execs_1) >= 1:
|
||||
print(f"✓ Matched list criteria (status='critical')")
|
||||
|
||||
# Step 4: Test with non-matching status
|
||||
print("\n[STEP 4] Test: status='low' (should NOT match)...")
|
||||
client.post_webhook(trigger_ref, {"status": "low", "message": "Low priority alert"})
|
||||
time.sleep(3)
|
||||
|
||||
execs_2 = client.list_executions(action=action_ref)
|
||||
print(f" Executions: {len(execs_2)}")
|
||||
if len(execs_2) == len(execs_1):
|
||||
print(f"✓ Did not match (status='low' not in list)")
|
||||
|
||||
# Step 5: Test with another matching status
|
||||
print("\n[STEP 5] Test: status='urgent' (should match)...")
|
||||
client.post_webhook(trigger_ref, {"status": "urgent", "message": "Urgent alert"})
|
||||
time.sleep(3)
|
||||
|
||||
execs_3 = client.list_executions(action=action_ref)
|
||||
print(f" Executions: {len(execs_3)}")
|
||||
if len(execs_3) > len(execs_2):
|
||||
print(f"✓ Matched list criteria (status='urgent')")
|
||||
|
||||
# Summary
|
||||
print("\n" + "=" * 80)
|
||||
print("LIST MEMBERSHIP CRITERIA TEST SUMMARY")
|
||||
print("=" * 80)
|
||||
print(f"✓ List membership (in operator) tested")
|
||||
print(f"✓ 'critical' status: matched")
|
||||
print(f"✓ 'low' status: filtered out")
|
||||
print(f"✓ 'urgent' status: matched")
|
||||
print("\n✅ LIST MEMBERSHIP CRITERIA WORKING!")
|
||||
print("=" * 80)
|
||||
Reference in New Issue
Block a user