re-uploading work
This commit is contained in:
335
tests/e2e/tier3/test_t3_02_timer_cancellation.py
Normal file
335
tests/e2e/tier3/test_t3_02_timer_cancellation.py
Normal file
@@ -0,0 +1,335 @@
|
||||
"""
|
||||
T3.2: Timer Cancellation Test
|
||||
|
||||
Tests that disabling a rule stops timer from executing, and re-enabling
|
||||
resumes executions.
|
||||
|
||||
Priority: LOW
|
||||
Duration: ~15 seconds
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from helpers.client import AttuneClient
|
||||
from helpers.fixtures import create_echo_action, create_interval_timer, unique_ref
|
||||
from helpers.polling import wait_for_execution_count
|
||||
|
||||
|
||||
@pytest.mark.tier3
|
||||
@pytest.mark.timer
|
||||
@pytest.mark.rules
|
||||
def test_timer_cancellation_via_rule_disable(client: AttuneClient, test_pack):
|
||||
"""
|
||||
Test that disabling a rule stops timer executions.
|
||||
|
||||
Flow:
|
||||
1. Create interval timer (every 3 seconds)
|
||||
2. Wait for 2 executions
|
||||
3. Disable rule
|
||||
4. Wait 10 seconds
|
||||
5. Verify no new executions occurred
|
||||
"""
|
||||
print("\n" + "=" * 80)
|
||||
print("T3.2a: Timer Cancellation via Rule Disable Test")
|
||||
print("=" * 80)
|
||||
|
||||
pack_ref = test_pack["ref"]
|
||||
|
||||
# Step 1: Create interval timer and action
|
||||
print("\n[STEP 1] Creating interval timer (every 3 seconds)...")
|
||||
trigger_ref = f"cancel_timer_{unique_ref()}"
|
||||
|
||||
trigger_response = create_interval_timer(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
trigger_ref=trigger_ref,
|
||||
interval=3,
|
||||
)
|
||||
|
||||
print(f"✓ Interval timer created: {trigger_ref}")
|
||||
print(f" Interval: 3 seconds")
|
||||
|
||||
# Step 2: Create action and rule
|
||||
print("\n[STEP 2] Creating action and rule...")
|
||||
action_ref = create_echo_action(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
message="Timer tick",
|
||||
suffix="_cancel",
|
||||
)
|
||||
|
||||
rule_data = {
|
||||
"name": f"Timer Cancellation Test Rule {unique_ref()}",
|
||||
"trigger": trigger_ref,
|
||||
"action": action_ref,
|
||||
"enabled": True,
|
||||
}
|
||||
|
||||
rule_response = client.create_rule(rule_data)
|
||||
rule_id = rule_response["id"]
|
||||
print(f"✓ Rule created: {rule_id}")
|
||||
print(f" Status: enabled")
|
||||
|
||||
# Step 3: Wait for 2 executions
|
||||
print("\n[STEP 3] Waiting for 2 timer executions...")
|
||||
wait_for_execution_count(
|
||||
client=client,
|
||||
action_ref=action_ref,
|
||||
expected_count=2,
|
||||
timeout=15,
|
||||
operator=">=",
|
||||
)
|
||||
|
||||
executions_before_disable = client.list_executions(action=action_ref)
|
||||
print(f"✓ {len(executions_before_disable)} executions occurred")
|
||||
|
||||
# Step 4: Disable rule
|
||||
print("\n[STEP 4] Disabling rule...")
|
||||
update_data = {"enabled": False}
|
||||
client.update_rule(rule_id, update_data)
|
||||
print(f"✓ Rule disabled: {rule_id}")
|
||||
|
||||
# Step 5: Wait and verify no new executions
|
||||
print("\n[STEP 5] Waiting 10 seconds to verify no new executions...")
|
||||
time.sleep(10)
|
||||
|
||||
executions_after_disable = client.list_executions(action=action_ref)
|
||||
new_executions = len(executions_after_disable) - len(executions_before_disable)
|
||||
|
||||
print(f" Executions before disable: {len(executions_before_disable)}")
|
||||
print(f" Executions after disable: {len(executions_after_disable)}")
|
||||
print(f" New executions: {new_executions}")
|
||||
|
||||
if new_executions == 0:
|
||||
print(f"✓ No new executions (timer successfully stopped)")
|
||||
else:
|
||||
print(f"⚠ {new_executions} new execution(s) occurred after disable")
|
||||
|
||||
# Summary
|
||||
print("\n" + "=" * 80)
|
||||
print("TIMER CANCELLATION TEST SUMMARY")
|
||||
print("=" * 80)
|
||||
print(f"✓ Timer created: {trigger_ref} (3 second interval)")
|
||||
print(f"✓ Rule disabled after {len(executions_before_disable)} executions")
|
||||
print(f"✓ New executions after disable: {new_executions}")
|
||||
|
||||
if new_executions == 0:
|
||||
print("\n✅ TIMER CANCELLATION WORKING!")
|
||||
else:
|
||||
print("\n⚠️ Timer may still be firing after rule disable")
|
||||
|
||||
print("=" * 80)
|
||||
|
||||
# Allow some tolerance for in-flight executions (1 execution max)
|
||||
assert new_executions <= 1, (
|
||||
f"Expected 0-1 new executions after disable, got {new_executions}"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.tier3
|
||||
@pytest.mark.timer
|
||||
@pytest.mark.rules
|
||||
def test_timer_resume_after_re_enable(client: AttuneClient, test_pack):
|
||||
"""
|
||||
Test that re-enabling a disabled rule resumes timer executions.
|
||||
"""
|
||||
print("\n" + "=" * 80)
|
||||
print("T3.2b: Timer Resume After Re-enable Test")
|
||||
print("=" * 80)
|
||||
|
||||
pack_ref = test_pack["ref"]
|
||||
|
||||
# Step 1: Create timer and rule
|
||||
print("\n[STEP 1] Creating timer and rule...")
|
||||
trigger_ref = f"resume_timer_{unique_ref()}"
|
||||
|
||||
create_interval_timer(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
trigger_ref=trigger_ref,
|
||||
interval=3,
|
||||
)
|
||||
|
||||
action_ref = create_echo_action(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
message="Resume test",
|
||||
suffix="_resume",
|
||||
)
|
||||
|
||||
rule_data = {
|
||||
"name": f"Timer Resume Test Rule {unique_ref()}",
|
||||
"trigger": trigger_ref,
|
||||
"action": action_ref,
|
||||
"enabled": True,
|
||||
}
|
||||
|
||||
rule_response = client.create_rule(rule_data)
|
||||
rule_id = rule_response["id"]
|
||||
print(f"✓ Timer and rule created")
|
||||
|
||||
# Step 2: Wait for 1 execution
|
||||
print("\n[STEP 2] Waiting for initial execution...")
|
||||
wait_for_execution_count(
|
||||
client=client,
|
||||
action_ref=action_ref,
|
||||
expected_count=1,
|
||||
timeout=10,
|
||||
operator=">=",
|
||||
)
|
||||
print(f"✓ Initial execution confirmed")
|
||||
|
||||
# Step 3: Disable rule
|
||||
print("\n[STEP 3] Disabling rule...")
|
||||
client.update_rule(rule_id, {"enabled": False})
|
||||
time.sleep(1)
|
||||
executions_after_disable = client.list_executions(action=action_ref)
|
||||
count_after_disable = len(executions_after_disable)
|
||||
print(f"✓ Rule disabled (executions: {count_after_disable})")
|
||||
|
||||
# Step 4: Wait while disabled
|
||||
print("\n[STEP 4] Waiting 6 seconds while disabled...")
|
||||
time.sleep(6)
|
||||
executions_still_disabled = client.list_executions(action=action_ref)
|
||||
count_still_disabled = len(executions_still_disabled)
|
||||
increase_while_disabled = count_still_disabled - count_after_disable
|
||||
print(f" Executions while disabled: {increase_while_disabled}")
|
||||
|
||||
# Step 5: Re-enable rule
|
||||
print("\n[STEP 5] Re-enabling rule...")
|
||||
client.update_rule(rule_id, {"enabled": True})
|
||||
print(f"✓ Rule re-enabled")
|
||||
|
||||
# Step 6: Wait for new executions
|
||||
print("\n[STEP 6] Waiting for executions to resume...")
|
||||
time.sleep(8)
|
||||
|
||||
executions_after_enable = client.list_executions(action=action_ref)
|
||||
count_after_enable = len(executions_after_enable)
|
||||
increase_after_enable = count_after_enable - count_still_disabled
|
||||
|
||||
print(f" Executions before re-enable: {count_still_disabled}")
|
||||
print(f" Executions after re-enable: {count_after_enable}")
|
||||
print(f" New executions: {increase_after_enable}")
|
||||
|
||||
if increase_after_enable >= 1:
|
||||
print(f"✓ Timer resumed (new executions after re-enable)")
|
||||
else:
|
||||
print(f"⚠ Timer did not resume")
|
||||
|
||||
# Summary
|
||||
print("\n" + "=" * 80)
|
||||
print("TIMER RESUME TEST SUMMARY")
|
||||
print("=" * 80)
|
||||
print(f"✓ Timer disabled: verified no new executions")
|
||||
print(f"✓ Timer re-enabled: {increase_after_enable} new execution(s)")
|
||||
|
||||
if increase_after_enable >= 1:
|
||||
print("\n✅ TIMER RESUME WORKING!")
|
||||
else:
|
||||
print("\n⚠️ Timer did not resume after re-enable")
|
||||
|
||||
print("=" * 80)
|
||||
|
||||
assert increase_after_enable >= 1, "Timer should resume after re-enable"
|
||||
|
||||
|
||||
@pytest.mark.tier3
|
||||
@pytest.mark.timer
|
||||
@pytest.mark.rules
|
||||
def test_timer_delete_stops_executions(client: AttuneClient, test_pack):
|
||||
"""
|
||||
Test that deleting a rule stops timer executions permanently.
|
||||
"""
|
||||
print("\n" + "=" * 80)
|
||||
print("T3.2c: Timer Delete Stops Executions Test")
|
||||
print("=" * 80)
|
||||
|
||||
pack_ref = test_pack["ref"]
|
||||
|
||||
# Step 1: Create timer and rule
|
||||
print("\n[STEP 1] Creating timer and rule...")
|
||||
trigger_ref = f"delete_timer_{unique_ref()}"
|
||||
|
||||
create_interval_timer(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
trigger_ref=trigger_ref,
|
||||
interval=3,
|
||||
)
|
||||
|
||||
action_ref = create_echo_action(
|
||||
client=client,
|
||||
pack_ref=pack_ref,
|
||||
message="Delete test",
|
||||
suffix="_delete",
|
||||
)
|
||||
|
||||
rule_data = {
|
||||
"name": f"Timer Delete Test Rule {unique_ref()}",
|
||||
"trigger": trigger_ref,
|
||||
"action": action_ref,
|
||||
"enabled": True,
|
||||
}
|
||||
|
||||
rule_response = client.create_rule(rule_data)
|
||||
rule_id = rule_response["id"]
|
||||
print(f"✓ Timer and rule created")
|
||||
|
||||
# Step 2: Wait for 1 execution
|
||||
print("\n[STEP 2] Waiting for initial execution...")
|
||||
wait_for_execution_count(
|
||||
client=client,
|
||||
action_ref=action_ref,
|
||||
expected_count=1,
|
||||
timeout=10,
|
||||
operator=">=",
|
||||
)
|
||||
|
||||
executions_before_delete = client.list_executions(action=action_ref)
|
||||
print(f"✓ Initial executions: {len(executions_before_delete)}")
|
||||
|
||||
# Step 3: Delete rule
|
||||
print("\n[STEP 3] Deleting rule...")
|
||||
try:
|
||||
client.delete_rule(rule_id)
|
||||
print(f"✓ Rule deleted: {rule_id}")
|
||||
except Exception as e:
|
||||
print(f"⚠ Rule deletion failed: {e}")
|
||||
pytest.skip("Rule deletion not available")
|
||||
|
||||
# Step 4: Wait and verify no new executions
|
||||
print("\n[STEP 4] Waiting 10 seconds to verify no new executions...")
|
||||
time.sleep(10)
|
||||
|
||||
executions_after_delete = client.list_executions(action=action_ref)
|
||||
new_executions = len(executions_after_delete) - len(executions_before_delete)
|
||||
|
||||
print(f" Executions before delete: {len(executions_before_delete)}")
|
||||
print(f" Executions after delete: {len(executions_after_delete)}")
|
||||
print(f" New executions: {new_executions}")
|
||||
|
||||
if new_executions == 0:
|
||||
print(f"✓ No new executions (timer permanently stopped)")
|
||||
else:
|
||||
print(f"⚠ {new_executions} new execution(s) after rule deletion")
|
||||
|
||||
# Summary
|
||||
print("\n" + "=" * 80)
|
||||
print("TIMER DELETE TEST SUMMARY")
|
||||
print("=" * 80)
|
||||
print(f"✓ Rule deleted: {rule_id}")
|
||||
print(f"✓ New executions after delete: {new_executions}")
|
||||
|
||||
if new_executions == 0:
|
||||
print("\n✅ TIMER DELETION STOPS EXECUTIONS!")
|
||||
else:
|
||||
print("\n⚠️ Timer may still fire after rule deletion")
|
||||
|
||||
print("=" * 80)
|
||||
|
||||
# Allow 1 in-flight execution tolerance
|
||||
assert new_executions <= 1, (
|
||||
f"Expected 0-1 new executions after delete, got {new_executions}"
|
||||
)
|
||||
Reference in New Issue
Block a user