61 lines
3.8 KiB
Python
61 lines
3.8 KiB
Python
"""Opt-in persistence/concurrency checks on the disposable BMC clone only."""
|
|
from concurrent.futures import ThreadPoolExecutor
|
|
from threading import Barrier
|
|
import pytest
|
|
from psycopg2.extras import RealDictCursor
|
|
from test_workflow_db import db
|
|
from app.core.database import atomic_transaction
|
|
from app.workflows import customer_activation as api,integration
|
|
|
|
@pytest.fixture
|
|
def activation_customer(db):
|
|
with db.cursor(cursor_factory=RealDictCursor) as cursor:
|
|
cursor.execute('SELECT id FROM customers ORDER BY id LIMIT 1')
|
|
customer=cursor.fetchone()['id']
|
|
cursor.execute('SELECT user_id FROM users ORDER BY user_id LIMIT 1')
|
|
actor=cursor.fetchone()['user_id']
|
|
cursor.execute('SELECT * FROM bmc_workflow_customer_activation WHERE customer_id=%s',(customer,))
|
|
previous=cursor.fetchone()
|
|
cursor.execute('SELECT COALESCE(MAX(id),0) AS id FROM bmc_workflow_customer_activation_history')
|
|
history_start=cursor.fetchone()['id']
|
|
cursor.execute('DELETE FROM bmc_workflow_customer_activation WHERE customer_id=%s',(customer,))
|
|
yield customer,{'id':actor,'username':'integration-test','is_superadmin':True},history_start
|
|
with db.cursor() as cursor:
|
|
cursor.execute('DELETE FROM bmc_workflow_customer_activation_history WHERE customer_id=%s AND id>%s',(customer,history_start))
|
|
cursor.execute('DELETE FROM bmc_workflow_customer_activation WHERE customer_id=%s',(customer,))
|
|
if previous:
|
|
cursor.execute('INSERT INTO bmc_workflow_customer_activation(customer_id,enabled,updated_by,updated_at) VALUES(%s,%s,%s,%s)',(customer,previous['enabled'],previous['updated_by'],previous['updated_at']))
|
|
|
|
def test_saved_override_is_persistent_and_master_off_stays_off(db,activation_customer,monkeypatch):
|
|
customer,actor,_=activation_customer
|
|
monkeypatch.setattr(integration.settings,'WORKFLOWS_ENABLED',False)
|
|
monkeypatch.setattr(integration.settings,'WORKFLOWS_MODE','active')
|
|
monkeypatch.setattr(integration.settings,'WORKFLOWS_CUSTOMER_IDS',[])
|
|
result=api.set_activation(customer,api.ActivationUpdate(enabled=True,reason='Disposable persistence test'),user=actor,workflow_access=actor)
|
|
assert result['enabled'] is True and result['effective_enabled'] is False
|
|
assert integration.customer_enabled(customer) is True
|
|
assert integration.active_for_customer(customer) is False
|
|
disabled=api.set_activation(customer,api.ActivationUpdate(enabled=False,reason='Disabled override test'),user=actor,workflow_access=actor)
|
|
assert disabled['explicit_override'] is False
|
|
with atomic_transaction() as connection:
|
|
with connection.cursor(cursor_factory=RealDictCursor) as cursor:
|
|
assert integration.customer_enabled(customer,cursor,fallback_ids=[customer]) is False
|
|
|
|
def test_concurrent_first_overrides_preserve_correct_audit_chain(db,activation_customer):
|
|
customer,actor,history_start=activation_customer
|
|
barrier=Barrier(2)
|
|
def write(enabled):
|
|
barrier.wait(timeout=10)
|
|
return api.set_activation(customer,api.ActivationUpdate(enabled=enabled,reason='Concurrent disposable test'),user=actor,workflow_access=actor)
|
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
|
results=list(pool.map(write,[True,False]))
|
|
assert len(results)==2
|
|
with db.cursor(cursor_factory=RealDictCursor) as cursor:
|
|
cursor.execute('SELECT before_enabled,after_enabled FROM bmc_workflow_customer_activation_history WHERE customer_id=%s AND id>%s ORDER BY id',(customer,history_start))
|
|
history=cursor.fetchall()
|
|
assert len(history)==2
|
|
assert history[0]['before_enabled'] is None
|
|
assert history[1]['before_enabled']==history[0]['after_enabled']
|
|
cursor.execute('SELECT enabled FROM bmc_workflow_customer_activation WHERE customer_id=%s',(customer,))
|
|
assert cursor.fetchone()['enabled']==history[1]['after_enabled']
|