from contextlib import contextmanager from unittest.mock import MagicMock from app.workflows import worker, classification class Cursor: def __init__(self,enabled=True): self.statements=[] self.enabled=enabled self.rows=[] def execute(self,sql,params=None): self.statements.append((sql,params)) if 'FROM bmc_workflow_runtime' in sql: self.rows=[{'enabled':self.enabled,'mode':'active','customer_ids':['24']}] elif 'FOR UPDATE SKIP LOCKED' in sql: self.rows=[{'id':'event1','entity_type':'time_entry','entity_id':'9','revision':1,'chain':[],'context':{},'trigger':'time.created'}] elif 'SELECT w.*' in sql: self.rows=[{'id':1,'priority':100,'customer_id':None,'version_id':2,'definition':{'trigger':'time.created','branches':[{'condition':None,'actions':[{'type':'set_billing','method':'invoice'}]}]}}] else: self.rows=[] def fetchone(self): return self.rows.pop(0) if self.rows else None def fetchall(self): rows,self.rows=self.rows,[] return rows def setup(monkeypatch,cursor): @contextmanager def transaction(): yield cursor monkeypatch.setattr(worker,'transaction',transaction) monkeypatch.setattr(worker,'load_time_context',lambda *args:{'time_id':9,'customer_id':'99','workflow_revision':1}) monkeypatch.setattr(classification,'enrich_time_context',lambda cursor,context:context) def test_disabled_runtime_never_dequeues(monkeypatch): cursor=Cursor(enabled=False) setup(monkeypatch,cursor) assert worker.process_pending_events(1)==0 assert len(cursor.statements)==1 def test_outside_allowlist_processes_only_shadow(monkeypatch): cursor=Cursor() setup(monkeypatch,cursor) assert worker.process_pending_events(1,mode='active')==1 sqls=[sql for sql,_ in cursor.statements] assert not any('INSERT INTO bmc_billing_decisions' in sql for sql in sqls) execution=next(params for sql,params in cursor.statements if 'INSERT INTO bmc_workflow_executions' in sql) assert execution[1]=='shadow' assert execution[2].adapted['mode']=='shadow'