@@ -104,12 +104,12 @@ def test_dismissal_validation_at_creation_time():
104
104
105
105
def test_dismissal_expiry_bug_search_filters (db_session ):
106
106
"""
107
- Test that reproduces the dismissedUntil expiry bug with search filters.
107
+ Test that verifies the dismissedUntil expiry fix works correctly with search filters.
108
108
109
- This test demonstrates the bug where alerts with expired dismissedUntil
110
- don't appear in searches for dismissed == false.
109
+ This test demonstrates that alerts with expired dismissedUntil properly appear
110
+ in searches for dismissed == false after the watcher processes them .
111
111
112
- This test should FAIL due to the bug (without watcher running) .
112
+ This test should PASS with the fixed watcher implementation .
113
113
"""
114
114
tenant_id = SINGLE_TENANT_UUID
115
115
@@ -200,14 +200,14 @@ def test_dismissal_expiry_bug_search_filters(db_session):
200
200
cel_query = "dismissed == false" , # or !dismissed
201
201
)
202
202
203
- # BUG: This should return the alert because its dismissal has expired,
204
- # but it won 't because there's no background process updating the status
203
+ # Before watcher: Alert still appears dismissed in database because
204
+ # the enrichment hasn 't been updated yet (dismissal expired but database not updated)
205
205
non_dismissed_alerts_before = SearchEngine (tenant_id = tenant_id ).search_alerts (search_query_not_dismissed )
206
206
207
- # Demonstrate the bug exists - should return 0 because bug prevents proper filtering
207
+ # Before watcher runs: Database still shows alert as dismissed (expected behavior)
208
208
assert len (non_dismissed_alerts_before ) == 0 , (
209
- "Bug reproduction confirmed : Alert doesn't appear in non-dismissed filter after "
210
- "dismissUntil expires (this is the bug we're fixing )"
209
+ "Before watcher : Alert doesn't appear in non-dismissed filter because "
210
+ "database hasn't been updated yet (dismissal expired but enrichment not processed )"
211
211
)
212
212
213
213
# NOW APPLY THE FIX: Run dismissal expiry watcher
@@ -216,7 +216,7 @@ def test_dismissal_expiry_bug_search_filters(db_session):
216
216
# AFTER FIX: The alert should now appear correctly
217
217
non_dismissed_alerts_after = SearchEngine (tenant_id = tenant_id ).search_alerts (search_query_not_dismissed )
218
218
219
- # This should now PASS - proving our fix works
219
+ # After watcher runs: Alert should now appear in non-dismissed filter
220
220
assert len (non_dismissed_alerts_after ) == 1 , (
221
221
"FIXED: Alert now appears in non-dismissed filter after watcher processes expired dismissal"
222
222
)
@@ -226,10 +226,10 @@ def test_dismissal_expiry_bug_search_filters(db_session):
226
226
227
227
def test_dismissal_expiry_bug_sidebar_filter (db_session ):
228
228
"""
229
- Test that reproduces the bug specifically with sidebar "Not dismissed" filter.
229
+ Test that verifies sidebar "Not dismissed" filter works correctly after watcher processes expired dismissals .
230
230
231
231
This simulates the UI scenario described in the GitHub issue.
232
- This test should FAIL due to the bug .
232
+ This test should PASS with the fixed watcher implementation .
233
233
"""
234
234
tenant_id = SINGLE_TENANT_UUID
235
235
@@ -395,9 +395,9 @@ def test_dismissal_expiry_bug_sidebar_filter(db_session):
395
395
396
396
def test_dismissal_expiry_bug_with_cel_filter (db_session ):
397
397
"""
398
- Test the bug specifically with CEL-based filters like dismissed == false.
398
+ Test that CEL-based filters work correctly with dismissed == false after watcher processes expired dismissals .
399
399
400
- This test should FAIL due to the bug .
400
+ This test should PASS with the fixed watcher implementation .
401
401
"""
402
402
tenant_id = SINGLE_TENANT_UUID
403
403
@@ -475,13 +475,13 @@ def test_dismissal_expiry_bug_with_cel_filter(db_session):
475
475
cel_query = cel_expr ,
476
476
)
477
477
478
- # BUG: All of these should return 1 alert, but will return 0
478
+ # Before watcher: Database hasn't been updated yet, so filter won't find the alert
479
479
results_before = SearchEngine (tenant_id = tenant_id ).search_alerts (search_query )
480
480
481
- # Demonstrate the bug exists - should return 0 due to bug
481
+ # Before watcher runs: Database still shows alert as dismissed
482
482
assert len (results_before ) == 0 , (
483
- f"Bug reproduction : CEL expression '{ cel_expr } ' should return 1 alert "
484
- f"after dismissal expires, but returns { len ( results_before ) } due to bug "
483
+ f"Before watcher : CEL expression '{ cel_expr } ' returns 0 because "
484
+ f"database hasn't been updated yet (dismissal expired but not processed) "
485
485
)
486
486
487
487
# APPLY THE FIX: Run dismissal expiry watcher
@@ -500,7 +500,7 @@ def test_dismissal_expiry_bug_with_cel_filter(db_session):
500
500
# Should now return 1 alert correctly
501
501
results_after = SearchEngine (tenant_id = tenant_id ).search_alerts (search_query )
502
502
503
- # This should now PASS - proving our fix works
503
+ # After watcher runs: Should now work correctly
504
504
assert len (results_after ) == 1 , (
505
505
f"FIXED: CEL expression '{ cel_expr } ' now correctly returns 1 alert "
506
506
f"after watcher processes expired dismissal"
@@ -776,6 +776,70 @@ def test_dismissal_expiry_bug_fixed_with_watcher(db_session):
776
776
getattr (non_dismissed_alerts_after [0 ], 'disposable_dismissed' , None ) is None
777
777
778
778
779
+ def test_dismissal_expiry_boolean_comparison_fix (db_session ):
780
+ """
781
+ Test that specifically validates the boolean comparison fix in get_alerts_with_expired_dismissals.
782
+
783
+ This test ensures that the function correctly finds dismissed alerts stored with different boolean
784
+ formats across different database types, which was the root cause of the original bug.
785
+ """
786
+ from keep .api .bl .dismissal_expiry_bl import DismissalExpiryBl
787
+ import datetime
788
+ from keep .api .models .db .alert import AlertEnrichment
789
+
790
+ tenant_id = SINGLE_TENANT_UUID
791
+ current_time = datetime .datetime .now (datetime .timezone .utc )
792
+ past_time = current_time - datetime .timedelta (hours = 1 )
793
+ past_time_str = past_time .strftime ("%Y-%m-%dT%H:%M:%S.%fZ" )
794
+
795
+ # Test different boolean representations that might be encountered
796
+ test_cases = [
797
+ {
798
+ "fingerprint" : "boolean-test-True" ,
799
+ "dismissed" : "True" , # Capitalized string (common in JavaScript/Python serialization)
800
+ "description" : "Capitalized 'True' string"
801
+ },
802
+ {
803
+ "fingerprint" : "boolean-test-true" ,
804
+ "dismissed" : "true" , # Lowercase string (JSON standard)
805
+ "description" : "Lowercase 'true' string"
806
+ }
807
+ ]
808
+
809
+ created_enrichments = []
810
+ for test_case in test_cases :
811
+ enrichment = AlertEnrichment (
812
+ tenant_id = tenant_id ,
813
+ alert_fingerprint = test_case ["fingerprint" ],
814
+ enrichments = {
815
+ "dismissed" : test_case ["dismissed" ],
816
+ "dismissUntil" : past_time_str , # Expired timestamp
817
+ "status" : "suppressed"
818
+ },
819
+ timestamp = current_time
820
+ )
821
+ created_enrichments .append (enrichment )
822
+ db_session .add (enrichment )
823
+
824
+ db_session .commit ()
825
+
826
+ # Test that get_alerts_with_expired_dismissals finds all variations
827
+ expired_dismissals = DismissalExpiryBl .get_alerts_with_expired_dismissals (db_session )
828
+ found_fingerprints = {e .alert_fingerprint for e in expired_dismissals }
829
+
830
+ # Verify all test cases are found regardless of boolean format
831
+ for test_case in test_cases :
832
+ assert test_case ["fingerprint" ] in found_fingerprints , (
833
+ f"Boolean comparison fix should find dismissed alerts with { test_case ['description' ]} "
834
+ f"(found: { found_fingerprints } )"
835
+ )
836
+
837
+ # Verify the found enrichment has the expected data
838
+ test_found = next (e for e in expired_dismissals if e .alert_fingerprint == test_case ["fingerprint" ])
839
+ assert test_found .enrichments ["dismissed" ] == test_case ["dismissed" ]
840
+ assert test_found .enrichments ["dismissUntil" ] == past_time_str
841
+
842
+
779
843
def test_github_issue_5047_cel_filters_dismisseduntil_bug_fixed (db_session ):
780
844
"""
781
845
Explicit test that solves GitHub Issue #5047:
0 commit comments