From 6e6922c4acffd08d6b9d142fd5fd6bdea6615d6f Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 15:17:42 +0000 Subject: [PATCH] [autofix.ci] apply automated fixes --- .../conversation/messages_clean_policy.py | 2 + .../conversation/messages_clean_service.py | 37 ++++++++------ .../services/test_messages_clean_service.py | 48 ++++++------------- 3 files changed, 39 insertions(+), 48 deletions(-) diff --git a/api/services/retention/conversation/messages_clean_policy.py b/api/services/retention/conversation/messages_clean_policy.py index d36d1af00b..6e647b983b 100644 --- a/api/services/retention/conversation/messages_clean_policy.py +++ b/api/services/retention/conversation/messages_clean_policy.py @@ -50,6 +50,7 @@ class BillingDisabledPolicy(MessagesCleanPolicy): No special filter logic, just return all message ids. """ + def filter_message_ids( self, messages: Sequence[SimpleMessage], @@ -68,6 +69,7 @@ class BillingSandboxPolicy(MessagesCleanPolicy): - Respect grace period after subscription expiration - Safe default: if tenant mapping or plan is missing, do NOT delete """ + def __init__( self, plan_provider: Callable[[Sequence[str]], dict[str, SubscriptionPlan]], diff --git a/api/services/retention/conversation/messages_clean_service.py b/api/services/retention/conversation/messages_clean_service.py index a28bc1ba67..1bca4b3a76 100644 --- a/api/services/retention/conversation/messages_clean_service.py +++ b/api/services/retention/conversation/messages_clean_service.py @@ -33,7 +33,7 @@ class MessagesCleanService: """ Service for cleaning expired messages based on retention policies. - Compatible with non cloud edition (billing disabled): all messages in the time range will be deleted. + Compatible with non cloud edition (billing disabled): all messages in the time range will be deleted. If billing is enabled: only sandbox plan tenant messages are deleted (with whitelist and grace period support). """ @@ -96,7 +96,10 @@ class MessagesCleanService: logger.info( "clean_messages: start_from=%s, end_before=%s, batch_size=%s, policy=%s", - start_from, end_before, batch_size, policy, + start_from, + end_before, + batch_size, + policy, ) return cls( @@ -140,16 +143,13 @@ class MessagesCleanService: logger.info( "clean_messages: days=%s, end_before=%s, batch_size=%s, policy=%s", - days, end_before, batch_size, policy, + days, + end_before, + batch_size, + policy, ) - return cls( - policy=policy, - end_before=end_before, - start_from=None, - batch_size=batch_size, - dry_run=dry_run - ) + return cls(policy=policy, end_before=end_before, start_from=None, batch_size=batch_size, dry_run=dry_run) def run(self) -> dict[str, int]: """ @@ -188,7 +188,9 @@ class MessagesCleanService: logger.info( "clean_messages: start cleaning messages (dry_run=%s), start_from=%s, end_before=%s", - self._dry_run, self._start_from, self._end_before, + self._dry_run, + self._start_from, + self._end_before, ) while True: @@ -274,7 +276,9 @@ class MessagesCleanService: logger.info( "clean_messages (batch %s): processed %s messages, deleted %s messages", - stats["batches"], len(messages), messages_deleted, + stats["batches"], + len(messages), + messages_deleted, ) else: # Log random sample of message IDs that would be deleted (up to 10) @@ -283,14 +287,19 @@ class MessagesCleanService: logger.info( "clean_messages (batch %s, dry_run): would delete %s messages, sampling %s ids:", - stats["batches"], len(message_ids_to_delete), sample_size, + stats["batches"], + len(message_ids_to_delete), + sample_size, ) for msg_id in sampled_ids: logger.info("clean_messages (batch %s, dry_run) sample: message_id=%s", stats["batches"], msg_id) logger.info( "clean_messages completed: total batches: %s, total messages: %s, filtered messages: %s, total deleted: %s", - stats["batches"], stats["total_messages"], stats["filtered_messages"], stats["total_deleted"], + stats["batches"], + stats["total_messages"], + stats["filtered_messages"], + stats["total_deleted"], ) return stats diff --git a/api/tests/test_containers_integration_tests/services/test_messages_clean_service.py b/api/tests/test_containers_integration_tests/services/test_messages_clean_service.py index 3832da0688..29baa4d94f 100644 --- a/api/tests/test_containers_integration_tests/services/test_messages_clean_service.py +++ b/api/tests/test_containers_integration_tests/services/test_messages_clean_service.py @@ -320,7 +320,7 @@ class TestMessagesCleanServiceIntegration: policy = create_message_clean_policy() assert isinstance(policy, BillingDisabledPolicy) - + service = MessagesCleanService.from_time_range( policy=policy, start_from=datetime.datetime(2024, 1, 10, 0, 0, 0), @@ -345,9 +345,7 @@ class TestMessagesCleanServiceIntegration: # Related records of out-of-range message kept assert db.session.query(MessageFeedback).where(MessageFeedback.message_id == out_of_range_msg_id).count() == 1 - def test_no_messages_returns_empty_stats( - self, db_session_with_containers, mock_billing_enabled, mock_whitelist - ): + def test_no_messages_returns_empty_stats(self, db_session_with_containers, mock_billing_enabled, mock_whitelist): """Test cleaning when there are no messages to delete (B1).""" # Arrange end_before = datetime.datetime.now() - datetime.timedelta(days=30) @@ -372,9 +370,7 @@ class TestMessagesCleanServiceIntegration: assert stats["filtered_messages"] == 0 assert stats["total_deleted"] == 0 - def test_mixed_sandbox_and_paid_tenants( - self, db_session_with_containers, mock_billing_enabled, mock_whitelist - ): + def test_mixed_sandbox_and_paid_tenants(self, db_session_with_containers, mock_billing_enabled, mock_whitelist): """Test cleaning with mixed sandbox and paid tenants (B2).""" # Arrange - Create sandbox tenants with expired messages sandbox_tenants = [] @@ -456,9 +452,7 @@ class TestMessagesCleanServiceIntegration: == 0 ) - def test_cursor_pagination_multiple_batches( - self, db_session_with_containers, mock_billing_enabled, mock_whitelist - ): + def test_cursor_pagination_multiple_batches(self, db_session_with_containers, mock_billing_enabled, mock_whitelist): """Test cursor pagination works correctly across multiple batches (B3).""" # Arrange - Create sandbox tenant with messages that will span multiple batches account, tenant = self._create_account_and_tenant(plan=CloudPlan.SANDBOX) @@ -505,9 +499,7 @@ class TestMessagesCleanServiceIntegration: # All messages should be deleted assert db.session.query(Message).where(Message.id.in_(message_ids)).count() == 0 - def test_dry_run_does_not_delete( - self, db_session_with_containers, mock_billing_enabled, mock_whitelist - ): + def test_dry_run_does_not_delete(self, db_session_with_containers, mock_billing_enabled, mock_whitelist): """Test dry_run mode does not delete messages (B4).""" # Arrange account, tenant = self._create_account_and_tenant(plan=CloudPlan.SANDBOX) @@ -551,9 +543,7 @@ class TestMessagesCleanServiceIntegration: # Related records should also still exist assert db.session.query(MessageFeedback).where(MessageFeedback.message_id.in_(message_ids)).count() == 3 - def test_partial_plan_data_safe_default( - self, db_session_with_containers, mock_billing_enabled, mock_whitelist - ): + def test_partial_plan_data_safe_default(self, db_session_with_containers, mock_billing_enabled, mock_whitelist): """Test when billing returns partial data, unknown tenants are preserved (B5).""" # Arrange - Create 3 tenants tenants_data = [] @@ -620,9 +610,7 @@ class TestMessagesCleanServiceIntegration: db.session.query(Message).where(Message.id == tenants_data[2]["message_id"]).count() == 1 ) # Unknown tenant's message preserved (safe default) - def test_empty_plan_data_skips_deletion( - self, db_session_with_containers, mock_billing_enabled, mock_whitelist - ): + def test_empty_plan_data_skips_deletion(self, db_session_with_containers, mock_billing_enabled, mock_whitelist): """Test when billing returns empty data, skip deletion entirely (B6).""" # Arrange account, tenant = self._create_account_and_tenant(plan=CloudPlan.SANDBOX) @@ -657,9 +645,7 @@ class TestMessagesCleanServiceIntegration: # Message should still exist (safe default - don't delete if plan is unknown) assert db.session.query(Message).where(Message.id == msg_id).count() == 1 - def test_time_range_boundary_behavior( - self, db_session_with_containers, mock_billing_enabled, mock_whitelist - ): + def test_time_range_boundary_behavior(self, db_session_with_containers, mock_billing_enabled, mock_whitelist): """Test that messages are correctly filtered by [start_from, end_before) time range (B7).""" # Arrange account, tenant = self._create_account_and_tenant(plan=CloudPlan.SANDBOX) @@ -745,9 +731,7 @@ class TestMessagesCleanServiceIntegration: # After range, kept assert db.session.query(Message).where(Message.id == msg_after_id).count() == 1 - def test_grace_period_scenarios( - self, db_session_with_containers, mock_billing_enabled, mock_whitelist - ): + def test_grace_period_scenarios(self, db_session_with_containers, mock_billing_enabled, mock_whitelist): """Test cleaning with different graceful period scenarios (B8).""" # Arrange - Create 5 different tenants with different plan and expiration scenarios now_timestamp = int(datetime.datetime.now(datetime.UTC).timestamp()) @@ -836,9 +820,9 @@ class TestMessagesCleanServiceIntegration: service = MessagesCleanService.from_time_range( policy=policy, start_from=datetime.datetime.now() - datetime.timedelta(days=60), - end_before=end_before, - batch_size=100, - ) + end_before=end_before, + batch_size=100, + ) stats = service.run() # Assert - Only messages from scenario 2 and 3 should be deleted @@ -853,9 +837,7 @@ class TestMessagesCleanServiceIntegration: assert db.session.query(Message).where(Message.id == msg4_id).count() == 1 # Professional plan, kept assert db.session.query(Message).where(Message.id == msg5_id).count() == 1 # At boundary, kept - def test_tenant_whitelist( - self, db_session_with_containers, mock_billing_enabled, mock_whitelist - ): + def test_tenant_whitelist(self, db_session_with_containers, mock_billing_enabled, mock_whitelist): """Test that whitelisted tenants' messages are not deleted (B9).""" # Arrange - Create 3 sandbox tenants with expired messages tenants_data = [] @@ -922,9 +904,7 @@ class TestMessagesCleanServiceIntegration: # Verify tenant2's message was deleted (not whitelisted) assert db.session.query(Message).where(Message.id == tenants_data[2]["message_id"]).count() == 0 - def test_from_days_cleans_old_messages( - self, db_session_with_containers, mock_billing_enabled, mock_whitelist - ): + def test_from_days_cleans_old_messages(self, db_session_with_containers, mock_billing_enabled, mock_whitelist): """Test from_days correctly cleans messages older than N days (B11).""" # Arrange account, tenant = self._create_account_and_tenant(plan=CloudPlan.SANDBOX)