
    Uit                       d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
Z
ddlZddlmZ ddlmZmZmZ ddlmZmZ ddlmZmZ ddlZej2                  j5                  d e ee      j:                  j:                  j:                               ddlmZm Z m!Z!m"Z"m#Z#m$Z$ dd	l%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/ dd
l0m1Z1m2Z2  e       Z3 e       Z4 e       Z5 G d d      Z6 G d d      Z7 G d d      Z8d$dZ9 G d d      Z: G d d      Z; G d d      Z< G d d      Z= G d d      Z> G d d      Z? G d d      Z@ G d  d!      ZA G d" d#      ZBy)%ar  RLM Neo-Cortex -- Module 2: Entitlement Ledger Integration Tests.

Story 2.08 integration test covering the full entitlement lifecycle:
  - Tier capability definitions (Story 2.01)
  - get_manifest with cache (Story 2.02)
  - update_tier with cache invalidation (Story 2.03)
  - check_quota with Redis counter (Story 2.04)
  - register_tenant (Story 2.05)
  - RlmTenant ORM model (Story 2.06)
  - Stripe webhook handler (Story 2.07)

All tests mock PostgreSQL and Redis -- no real Elestio connections required.

VERIFICATION_STAMP
Story: 2.08
Verified By: parallel-builder
Verified At: 2026-02-26
Tests: 37/37
Coverage: >=85%
    )annotationsN)Path)AnyDictOptional)	MagicMockpatch)UUIDuuid4)CustomerTierEntitlementManifestFeedbackSignalMemoryRecord
MemoryTierPreferencePair)
TIER_CAPABILITIESEntitlementLedgerTenantAlreadyExistsErrorTenantNotFoundError_CACHE_PREFIX_CACHE_TTL_SECONDS_QUOTA_PREFIX_build_manifest_deserialize_manifest_serialize_manifest)PRICE_TO_TIERhandle_stripe_eventc                  `    e Zd ZdZddZddZddZddZddZddZ	ddZ
dd	Zdd
ZddZy)	FakeRediszCIn-memory Redis mock supporting GET/SET/DEL/INCR/EXPIRE/PING/SETEX.c                     i | _         i | _        y N_store_ttlsselfs    3/mnt/e/genesis-system/tests/rlm/test_entitlement.py__init__zFakeRedis.__init__J   s    &(%'
    c                     yNT r%   s    r'   pingzFakeRedis.pingN   s    r)   c                8    | j                   j                  |      S r!   )r#   getr&   keys     r'   r/   zFakeRedis.getQ   s    {{s##r)   c                @    || j                   |<   || j                  |<   y r!   r"   )r&   r1   ttlvalues       r'   setexzFakeRedis.setexT   s     C

3r)   c                    || j                   v }| j                   j                  |d        | j                  j                  |d        |rdS dS )N   r   )r#   popr$   )r&   r1   existeds      r'   deletezFakeRedis.deleteX   sA    $T"

sD!q""r)   c                    t        | j                  j                  |d            }|dz   }t        |      | j                  |<   |S )N0r7   )intr#   r/   str)r&   r1   currentnew_vals       r'   incrzFakeRedis.incr^   s;    dkkooc3/0A+w<Cr)   c                "    || j                   |<   yr+   )r$   )r&   r1   r3   s      r'   expirezFakeRedis.expired   s    

3r)   c                     y r!   r,   r%   s    r'   closezFakeRedis.closeh       r)   c                    || j                   v S r!   )r#   r0   s     r'   _has_keyzFakeRedis._has_keyl   s    dkk!!r)   c                8    | j                   j                  |      S r!   )r$   r/   r0   s     r'   _get_ttlzFakeRedis._get_ttlo   s    zz~~c""r)   NreturnNone)rL   bool)r1   r>   rL   zOptional[str])r1   r>   r3   r=   r4   r>   rL   rM   )r1   r>   rL   r=   )r1   r>   r3   r=   rL   rN   )r1   r>   rL   rN   )r1   r>   rL   zOptional[int])__name__
__module____qualname____doc__r(   r-   r/   r5   r:   rA   rC   rE   rH   rJ   r,   r)   r'   r   r   G   s7    M($#"#r)   r   c                  6    e Zd ZdZddZd	d
dZddZd Zd Zy)FakePgCursorz#Minimal cursor mock for PostgreSQL.c                .    || _         d| _        d | _        y )Nr   )_connrowcount_result)r&   
connections     r'   r(   zFakePgCursor.__init__v   s    
r)   c                D   |j                         j                         }|j                  d      rd|v rd|v r|r|d   nd }| j                  j                  j                  |      }|rd|v r|j                  dd      f| _        n|d   |d   |j                  d	      |j                  d
      |j                  dd      |j                  dd      |j                  d      |j                  d      |j                  dd      f	| _        nd | _        | j                  rdnd| _        y y y |j                  d      rd|v rd|vr||d   }|| j                  j                  v rt        d      ||d   t        |      dkD  r|d   nd t        |      dkD  r|d   ndddd d d d	| j                  j                  |<   d| _        y d|v r-| j                  j                  j                  |       d| _        y y |j                  d      rd|v rd|v rA|d   }| j                  j                  j                  |      }|rd|d<   d| _        y d| _        y |d   }|d   }| j                  j                  j                  |      }|r|j                  dd      r||d<   d| _        y d| _        y y y )Nselectrlm_tenantszwhere tenant_idr   zselect total_memoriestotal_memories	tenant_idtierstripe_customer_idstripe_subscription_idmemory_usage_mb        
created_at
updated_at	is_activeTr7   insertrlm_tenants_auditz.duplicate key value violates unique constraint      )	r^   r_   r`   rf   rb   r]   rd   re   ra   updatezis_active = falseF)striplower
startswithrV   _tenantsr/   rX   rW   	Exceptionlen_audit_writesappend)r&   queryparamsquery_lowertidrownew_tiers          r'   executezFakePgCursor.execute{   s   kkm))+!!(++0A[0P#)fQitjj))--c2.+=(+0@!(D'F  ,KGG$89GG$<=GG$5s;GG$4a8GGL1GGL1GGK6
( $(DL%)\\q+ 1Q+. ##H-+0C;0VQi$**---#$TUU!$"1I7:6{Q&)D.1&kAo4'*&'"&"&.2
,

##C( !"$3

((//7 ! 4
 ##H-+&+5 )C**--11#6C+0K(()()  &ayH )C**--11#6Csww{D9&.F()()% , .r)   c                    | j                   S r!   )rX   r%   s    r'   fetchonezFakePgCursor.fetchone   s    ||r)   c                    | S r!   r,   r%   s    r'   	__enter__zFakePgCursor.__enter__   s    r)   c                     y r!   r,   )r&   argss     r'   __exit__zFakePgCursor.__exit__   rF   r)   N)rY   z'FakePgConnection'rL   rM   )r,   )rt   r>   ru   tuplerL   rM   )rL   zOptional[tuple])	rO   rP   rQ   rR   r(   rz   r|   r~   r   r,   r)   r'   rT   rT   s   s     -
E*Nr)   rT   c                  8    e Zd ZdZddZd	dZddZddZddZy)
FakePgConnectionz#Minimal PostgreSQL connection mock.c                .    i | _         g | _        d| _        y )NF)ro   rr   
autocommitr%   s    r'   r(   zFakePgConnection.__init__   s    35#%r)   c                    t        |       S r!   )rT   r%   s    r'   cursorzFakePgConnection.cursor   s    D!!r)   c                     y r!   r,   r%   s    r'   commitzFakePgConnection.commit   rF   r)   c                     y r!   r,   r%   s    r'   rollbackzFakePgConnection.rollback   rF   r)   c                     y r!   r,   r%   s    r'   rE   zFakePgConnection.close   rF   r)   NrK   )rL   rT   )	rO   rP   rQ   rR   r(   r   r   r   rE   r,   r)   r'   r   r      s    - 
"r)   r   c                 x    t        dd      } t               }t               }|| _        || _        d| _        | ||fS )z<Create an EntitlementLedger with fake PG and Redis backends.zfake://)pg_dsn	redis_urlT)r   r   r   _redis_pg_conn
_connected)ledger
fake_redisfake_pgs      r'   _make_ledgerr      s@    i9EFJ GFMFOF:w&&r)   c                  `    e Zd ZdZddZddZddZddZddZddZ	ddZ
dd	Zdd
ZddZy)TestTierCapabilitieszStory 2.01 -- BB1-BB3, WB1-WB2.c                <   t        t              }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               nddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	N   ==z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)srq   r   py0py1py3py6assert %(py8)spy8)
rq   r   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation)r&   @py_assert2@py_assert5@py_assert4@py_format7@py_format9s         r'   test_bb1_four_tier_entriesz/TestTierCapabilities.test_bb1_four_tier_entries   s    $%**%****%******s***s******$***$***%**********r)   c                2   t         t        j                     d   d   }d}||u }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nfeaturesvoice_agentFisz%(py1)s is %(py4)sr   py4assert %(py6)sr   r   r   STARTERr   r   r   r   r   r&   @py_assert0@py_assert3r   @py_format5r   s         r'   test_bb2_starter_no_voicez.TestTierCapabilities.test_bb2_starter_no_voice   sh     !5!56zB=QZUZZQUZZZZZQUZZZZQZZZUZZZZZZZZr)   c                8   t         t        j                     d   }d}| }||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )Nmax_memories_per_dayr7   r   z%(py1)s == -%(py4)sr   assert %(py7)spy7r   r   QUEENr   r   r   r   r   r&   r   r   r   r   @py_format6@py_format8s          r'   !test_bb3_queen_unlimited_memoriesz6TestTierCapabilities.test_bb3_queen_unlimited_memories   sm     !3!345KLRQRRQRPRRLPRRRRRLPRRRRLRRRQRRRRRRRRr)   c                   t         D ]  }|t        v }|st        j                  d|fd|t        f      dt	        j
                         v st        j                  |      rt        j                  |      nddt	        j
                         v st        j                  t              rt        j                  t              nddz  }t        j                  d|       dz   d|iz  }t        t        j                  |            d } y )	Ninz%(py0)s in %(py2)sr_   r   r   py2zMissing capabilities for 
>assert %(py4)sr   )r   r   r   r   r   r   r   r   _format_assertmsgr   r   )r&   r_   @py_assert1@py_format3r   s        r'   $test_wb1_all_tiers_have_capabilitiesz9TestTierCapabilities.test_wb1_all_tiers_have_capabilities   s      	QD,,PPP4,PPPPPP4PPP4PPPPPP,PPP,PPPP0I$.PPPPPPP	Qr)   c                l   t        j                         D ]  \  }}d}|d   }||v }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j
                  | d      dz   d|iz  }t        t        j                  |            d x}x}} y )	Nbasic_memoryr   r   )z%(py1)s in %(py4)sr   z missing basic_memory featurez
>assert %(py6)sr   )r   itemsr   r   r   r   r   r   )r&   r_   capsr   r   r   r   r   s           r'   $test_wb2_all_tiers_have_basic_memoryz9TestTierCapabilities.test_wb2_all_tiers_have_basic_memory  s    +113 	JD$! T*%5 >%55  >%5  I "  I &6    &56     	r)   c                2   t         t        j                     d   d   }d}||u }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nr   r   Tr   r   r   r   r   )r   r   PROFESSIONALr   r   r   r   r   r   s         r'   test_professional_has_voicez0TestTierCapabilities.test_professional_has_voice  sh     !:!:;JGV^Z^^VZ^^^^^VZ^^^^V^^^Z^^^^^^^^r)   c                2   t         t        j                     d   d   }d}||u }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nr   browser_useTr   r   r   r   r   )r   r   
ENTERPRISEr   r   r   r   r   r   s         r'   test_enterprise_has_browserz0TestTierCapabilities.test_enterprise_has_browser  sh     !8!89*EmT\X\\TX\\\\\TX\\\\T\\\X\\\\\\\\r)   c                8   t         t        j                     d   }d}| }||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )Nmemory_limit_mbr7   r   r   r   r   r   r   r   s          r'   !test_queen_memory_limit_unlimitedz6TestTierCapabilities.test_queen_memory_limit_unlimited  sg     !3!345FGMAMA2MG2MMMMG2MMMGMMMAMMMMMMMr)   c                .   t         t        j                     d   }d}||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )Ndecay_policy
aggressiver   z%(py1)s == %(py4)sr   r   r   r   r   s         r'   test_starter_decay_aggressivez2TestTierCapabilities.test_starter_decay_aggressive  s_     !5!56~FV,VF,VVVVF,VVVFVVV,VVVVVVVr)   c                .   t         t        j                     d   }d}||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )Nr   infiniter   r   r   r   r   r   r   s         r'   test_queen_decay_infinitez.TestTierCapabilities.test_queen_decay_infinite  s_     !3!34^DR
RD
RRRRD
RRRDRRR
RRRRRRRr)   NrK   )rO   rP   rQ   rR   r   r   r   r   r   r   r   r   r   r   r,   r)   r'   r   r      s?    )+[SQ
_]NWSr)   r   c                  2   e Zd ZdZej
                  j                  dd       Zej
                  j                  dd       Zej
                  j                  dd       Z	ej
                  j                  dd       Z
ej
                  j                  dd       Zy)	TestGetManifestzStory 2.02 -- BB1-BB3, WB1-WB2.c                  K   t               \  }}}|j                  t        t        j                         d {    |j                  t               d {   }|j                  }t        j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}|j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d	t        j                         v st        j                  t              rt        j                  t              nd	d
z  }
dd|
iz  }t        t        j                  |            d x}}y 7 C7 )w)Nr   zI%(py2)s
{%(py2)s = %(py0)s.tier
} == %(py6)s
{%(py6)s = %(py4)s.STARTER
}manifestr   r   r   r   r   r   r   z1%(py2)s
{%(py2)s = %(py0)s.tenant_id
} == %(py4)sTENANT_Ar   r   r   r   r   )r   register_tenantr   r   r   get_manifestr_   r   r   r   r   r   r   r   r   r^   )r&   r   r   r   r   r   r   r   r   r   r   s              r'   /test_bb1_registered_tenant_returns_correct_tierz?TestGetManifest.test_bb1_registered_tenant_returns_correct_tier"  sc    &2n#
G$$X|/C/CDDD,,X66}}4 4 44} 44444} 4444444x444x444}444444444444 44444444!!-!X----!X------x---x---!------X---X------- 	E6s"   6JI;JI>H&J>Jc                   K   t               \  }}}t        j                  t              5  |j	                  t                      d {    d d d        y 7 # 1 sw Y   y xY wwr!   )r   pytestraisesr   r   r   r&   r   _s      r'   (test_bb2_nonexistent_tenant_raises_errorz8TestGetManifest.test_bb2_nonexistent_tenant_raises_error*  sS     #~1]]./ 	/%%eg...	/ 	/.	/ 	/s.   (A#AAA	A#AA A#c                  K   t               \  }}}|j                  t        t        j                         d {    |j                  t               d {   }t         t         }|j                  } ||      }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        t        j                  |            d x}}|j                  t               d {   }	|	j                  }|j                  }
||
k(  }|st        j                   d|fd||
f      dt        j                         v st        j                  |	      rt        j                  |	      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |
      d	z  }d
d|iz  }t        t        j                  |            d x}x}}
y 7 I7 /7 w)NJassert %(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s._has_key
}(%(py3)s)
}r   	cache_keyr   r   r   py5r   )zF%(py2)s
{%(py2)s = %(py0)s.tier
} == %(py6)s
{%(py6)s = %(py4)s.tier
}	manifest2	manifest1r   r   r   )r   r   r   r   r   r   r   rH   r   r   r   r   r   r   r   r_   r   )r&   r   r   r   r	  r  r   r   r   r  r   r   r   r   s                 r'   !test_bb3_cache_hit_on_second_callz1TestGetManifest.test_bb3_cache_hit_on_second_call0  s    &2n#
G$$X|/C/CDDD !--h77	$ohZ0	""-"9--------z---z---"------9---9---------- !--h77	~~//~////~//////y///y///~/////////////////// 	E 8
 8s5   6J
JJ
JDJ
(J)DJ
J
J
c           
       K   t               \  }}}t        t              dd d ddd d dd	|j                  t        t              <   |j	                  t               d {   }|j
                  }t        j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }dd|iz  }	t        t        j                  |	            d x}x}}y 7 %w)Nprofessionalrc   r   T	r^   r_   r`   ra   rb   r]   rd   re   rf   r   zN%(py2)s
{%(py2)s = %(py0)s.tier
} == %(py6)s
{%(py6)s = %(py4)s.PROFESSIONAL
}r   r   r   r   r   )r   r>   r   ro   r   r_   r   r   r   r   r   r   r   r   r   r   )
r&   r   r   r   r   r   r   r   r   r   s
             r'   &test_wb1_cache_miss_triggers_pg_lookupz6TestGetManifest.test_wb1_cache_miss_triggers_pg_lookup>  s     &2n#
G X""&&*"
+
X'  ,,X66}}9 9 99} 99999} 9999999x999x999}999999999999 99999999 7s   AFFD%Fc           
     |  K   t               \  }}}t        t              dd d ddd d dd	|j                  t        t              <   |j	                  t               d {    t
         t         }|j                  } ||      }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d	z  }t        t        j                  |            d x}}|j                  } ||      }|t        k(  }|s;t        j                   d
|fd|t        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }	dd|	iz  }
t        t        j                  |
            d x}x}}y 7 ]w)Nstarterrc   r   Tr  r  r   r  r  r   )zN%(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s._get_ttl
}(%(py3)s)
} == %(py7)sr   )r   r   r   r  r   assert %(py9)spy9)r   r>   r   ro   r   r   rH   r   r   r   r   r   r   r   rJ   r   r   )r&   r   r   r   r  r   r   r   @py_assert6r   @py_format10s              r'   "test_wb2_pg_lookup_caches_with_ttlz2TestGetManifest.test_wb2_pg_lookup_caches_with_ttlP  s    &2n#
GX"&&*"
+
X' !!(+++$ohZ0	""-"9--------z---z---"------9---9----------""C"9-C-1CCCCC-1CCCCCCCzCCCzCCC"CCCCCC9CCC9CCC-CCCCCC1CCCC1CCCCCCCC 	,s   AJ<J9IJ<NrK   )rO   rP   rQ   rR   r   markasyncior   r  r
  r  r  r,   r)   r'   r   r     s    )[[. . [[/ /
 [[0 0 [[: :" [[D Dr)   r   c                  2   e Zd ZdZej
                  j                  dd       Zej
                  j                  dd       Zej
                  j                  dd       Z	ej
                  j                  dd       Z
ej
                  j                  dd       Zy)	TestUpdateTierzStory 2.03 -- BB1-BB3, WB1-WB2.c                4  K   t               \  }}}|j                  t        t        j                         d {    |j                  t        t        j                         d {   }|j                  }t        j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}|j                   d   }	d	}|	|u }
|
slt        j                  d
|
fd|	|f      t        j                  |	      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}	x}
}y 7 7 w)Nr   r  r   r   r   r   r   r   Tr   r   r   r   r   )r   r   r   r   r   update_tierr   r_   r   r   r   r   r   r   r   r   r   r&   r   r  r   r   r   r   r   r   r   r   r   s               r'   (test_bb1_upgrade_starter_to_professionalz7TestUpdateTier.test_bb1_upgrade_starter_to_professionalk  sA    #~1$$X|/C/CDDD++Hl6O6OPP}}9 9 99} 99999} 9999999x999x999}999999999999 99999999  /747/47777/4777/77747777777 	EPs"   6HH+H$H%F.HHc                p  K   t               \  }}}|j                  t        t        j                         d {    |j                  t        t        j                         d {   }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y 7 7 ϭw)Nd   r   z7%(py2)s
{%(py2)s = %(py0)s.memory_limit_mb
} == %(py5)sr   r   r   r  r   r   )r   r   r   r   r   r  r   r   r   r   r   r   r   r   r   r   )	r&   r   r  r   r   r   r   r   r   s	            r'   (test_bb2_downgrade_enterprise_to_starterz7TestUpdateTier.test_bb2_downgrade_enterprise_to_starters  s     #~1$$X|/F/FGGG++Hl6J6JKK''.3.'3....'3......x...x...'...3....... 	HKs"   6D6D2+D6$D4%CD64D6c                   K   t               \  }}}t        j                  t              5  |j	                  t               t        j                         d {    d d d        y 7 # 1 sw Y   y xY wwr!   )r   r   r   r   r  r   r   r   r   s      r'   (test_bb3_update_nonexistent_raises_errorz7TestUpdateTier.test_bb3_update_nonexistent_raises_errorz  s`     #~1]]./ 	D$$UWl.B.BCCC	D 	DC	D 	Ds.   (A2,A&A$A&	A2$A&&A/+A2c                  K   t               \  }}}|j                  t        t        j                         d {    t
         t         }|j                  } ||      }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        t        j                  |            d x}}|j                  t        t        j                         d {    t!        j"                  |j%                  |            }|d   }	d}
|	|
k(  }|slt        j&                  d|fd|	|
f      t        j                  |	      t        j                  |
      d	z  }d
d|iz  }t        t        j                  |            d x}	x}}
y 7 7 w)Nr  r   r  r  r_   r  r   r   r   r   r   )r   r   r   r   r   r   rH   r   r   r   r   r   r   r   r  r   jsonloadsr/   r   r&   r   r   r  r  r   r   r   cachedr   r   r   r   r   s                 r'   #test_wb1_redis_del_called_on_updatez2TestUpdateTier.test_wb1_redis_del_called_on_update  sO     ,
A$$X|/C/CDDD$ohZ0	 ""-"9--------z---z---"------9---9----------   <+D+DEEEJNN956f~//~////~///~////////// 	E 	Fs#   6H	HD!H	HB*H	H	c                h  K   t               \  }}}|j                  t        t        j                         d {    |j                  t        t        j                         d {    |j                  }t        |      }d}||k\  }|s
t        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                   |	            d x}x}x}}|j                  d	   }
|
d   }d
}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            d x}x}}|
d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            d x}x}}y 7 t7 Kw)Nr7   )>=)zS%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s._audit_writes
})
} >= %(py8)srq   r   )r   r   r   r  r   assert %(py10)spy10r  r   r   r   r   r   ri   
enterprise)r   r   r   r   r   r  r   rr   rq   r   r   r   r   r   r   r   r   )r&   r   r  r   r   r   @py_assert7r  r   @py_format11auditr   r   r   r   s                  r'   test_wb2_audit_event_writtenz+TestUpdateTier.test_wb2_audit_event_written  s    )^7$$X|/C/CDDD  <+B+BCCC((.s().Q.)Q....)Q......s...s......7...7...(...)...Q.......%%b)Qx$9$x9$$$$x9$$$x$$$9$$$$$$$Qx'<'x<''''x<'''x'''<''''''' 	ECs"   6J2J,+J2$J/%IJ2/J2NrK   )rO   rP   rQ   rR   r   r  r  r  r#  r%  r+  r5  r,   r)   r'   r  r  h  s    )[[8 8 [[/ / [[D D
 [[0 0 [[( (r)   r  c                  2   e Zd ZdZej
                  j                  dd       Zej
                  j                  dd       Zej
                  j                  dd       Z	ej
                  j                  dd       Z
ej
                  j                  dd       Zy)	TestCheckQuotazStory 2.04 -- BB1-BB3, WB1-WB2.c                  K   t               \  }}}|j                  t        t        j                         d {    |j                  t               d {   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y 7 7 w)NTr   r   r   r   r   )r   r   r   r   r   check_quotar   r   r   r   r   )	r&   r   r   r  r   r   r   r   r   s	            r'   !test_bb1_fresh_tenant_under_limitz0TestCheckQuota.test_bb1_fresh_tenant_under_limit  s      ,
A$$X|/C/CDDD''119T91T99991T9991999T9999999 	E1s"   6CCCCB CCc                Z  K   t               \  }}}|j                  t        t        j                         d {    ddlm}m} |j                  |j                        j                  d      }t         t         d| }d|j                  |<   |j                  t               d {   }d}	||	u }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      d	z  }d
d|iz  }t!        t        j"                  |            d x}x}
}	y 7 7 w)Nr   datetimetimezone%Y-%m-%d:500Fr   r   r   r   r   r   r   r   r   r   r=  r>  nowutcstrftimer   r#   r9  r   r   r   r   r   r&   r   r   r  r=  r>  today	quota_keyr   r   r   r   r   s                r'   &test_bb2_tenant_at_limit_returns_falsez5TestCheckQuota.test_bb2_tenant_at_limit_returns_false  s      ,
A$$X|/C/CDDD 	0X\\*33J?$ohZq8	',
)$''11:U:1U::::1U:::1:::U::::::: 	E 2#   6D+D'A.D+'D)(B D+)D+c                Z  K   t               \  }}}|j                  t        t        j                         d {    ddlm}m} |j                  |j                        j                  d      }t         t         d| }d|j                  |<   |j                  t               d {   }d}	||	u }
|
slt        j                  d|
fd||	f      t        j                  |      t        j                  |	      d	z  }d
d|iz  }t!        t        j"                  |            d x}x}
}	y 7 7 w)Nr   r<  r?  r@  100000Tr   r   r   r   r   )r   r   TENANT_QUEENr   r   r=  r>  rC  rD  rE  r   r#   r9  r   r   r   r   r   rF  s                r'   !test_bb3_queen_always_under_quotaz0TestCheckQuota.test_bb3_queen_always_under_quota  s      ,
A$$\<3E3EFFF/X\\*33J?$ol^1UG<	'/
)$''55==5====5===5========== 	G 6rJ  c                  K   t               \  }}}|j                  t        t        j                         d {    ddlm}m} |j                  |j                        j                  d      }t         t         d| }d|j                  |<   d|j                  t        t                 d<   |j                  t               d {   }d}	||	u }
|
slt        j                   d	|
fd
||	f      t        j"                  |      t        j"                  |	      dz  }dd|iz  }t%        t        j&                  |            d x}x}
}	y 7 7 w)Nr   r<  r?  r@  100iX  r]   Tr   r   r   r   r   )r   r   r   r   r   r=  r>  rC  rD  rE  r   r#   ro   r>   r9  r   r   r   r   r   )r&   r   r   r   r=  r>  rG  rH  r   r   r   r   r   s                r'   "test_wb1_uses_redis_counter_not_pgz1TestCheckQuota.test_wb1_uses_redis_counter_not_pg  s     &2n#
G$$X|/C/CDDD/X\\*33J?$ohZq8	 (-
)$<?X'(89 ''119T91T99991T9991999T9999999 	E 2s#   6EEBEE	B E	Ec                  K   t               \  }}}|j                  t        t        j                         d {    |j                  t               d {   }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y 7 7 w)NTr   )z%(py0)s is %(py3)sresultr   r   assert %(py5)sr  )r   r   rM  r   r   r9  r   r   r   r   r   r   r   r   )	r&   r   r   r  rS  r   r   @py_format4r   s	            r'   test_wb2_queen_short_circuitsz,TestCheckQuota.test_wb2_queen_short_circuits  s      ,
A$$\<3E3EFFF )),77v~vvv	 	G 8s"   6DD DDB+DDNrK   )rO   rP   rQ   rR   r   r  r  r:  rI  rN  rQ  rW  r,   r)   r'   r7  r7    s    )[[: :
 [[
; 
; [[	> 	> [[: :  [[ r)   r7  c                  2   e Zd ZdZej
                  j                  dd       Zej
                  j                  dd       Zej
                  j                  dd       Z	ej
                  j                  dd       Z
ej
                  j                  dd       Zy)	TestRegisterTenantzStory 2.05 -- BB1-BB3, WB1-WB2.c                  K   t               \  }}}|j                  t        t        j                         d {   }|j
                  }t        j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}|j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d	t        j                         v st        j                  t              rt        j                  t              nd	d
z  }
dd|
iz  }t        t        j                  |            d x}}t        t              }|j                   }||v }|s?t        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndd	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y 7 w)Nr   r   r   r   r   r   r   r   r   r   r   r   r   zN%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} in %(py7)s
{%(py7)s = %(py5)s._tenants
}r>   r   r   r   r   r  r   r  r  )r   r   r   r   r   r_   r   r   r   r   r   r   r   r   r^   r>   ro   )r&   r   r   r   r   r   r   r   r   r   r   r   r  r   r   r  s                   r'   test_bb1_register_new_tenantz/TestRegisterTenant.test_bb1_register_new_tenant  s    &2n#
G//,:N:NOO}}4 4 44} 44444} 4444444x444x444}444444444444 44444444!!-!X----!X------x---x---!------X---X-------8}0 0 00} 00000} 0000000s000s00000080008000}000000000000 00000000 Ps   6OONOc                <  K   t               \  }}}|j                  t        t        j                         d {    t        j                  t              5  |j                  t        t        j                         d {    d d d        y 7 S7 # 1 sw Y   y xY wwr!   	r   r   r   r   r   r   r   r   r   r   s      r'   ,test_bb2_duplicate_registration_raises_errorz?TestRegisterTenant.test_bb2_duplicate_registration_raises_error  s     #~1$$X|/C/CDDD]]34 	N((<3L3LMMM	N 	N 	EM	N 	N9   6BBB(B>B?B
BBBBc                  K   t               \  }}}|j                  t        t        j                  d       d {    |j
                  t        t                 }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}y 7 w)	N
cus_abc123)r`   r`   r   r   r   r   r   )r   r   r   r   r   ro   r>   r   r   r   r   r   )
r&   r   r  r   rx   r   r   r   r   r   s
             r'    test_bb3_register_with_stripe_idz3TestRegisterTenant.test_bb3_register_with_stripe_id  s     )^7$$l//L % 
 	
 	
 s8}-'(8L8(L8888(L888(888L8888888		
s   8CCB"Cc                  K   t               \  }}}|j                  t        t        j                         d{    t        t              }|j                  }||v }|s?t        j                  d|fd||f      dt        j                         v st        j                  t
              rt        j                  t
              nddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd	|iz  }t        t        j                  |            dx}x}}|j                  t        t                 d
   }	d}
|	|
k(  }|slt        j                  d|fd|	|
f      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}	x}}
y7 w)zIThe mock validates parameterized INSERT -- if it works, params were used.Nr   r[  r>   r   r   r\  r  r  r_   r  r   r   r   r   r   )r   r   r   r   r   r>   ro   r   r   r   r   r   r   r   r   )r&   r   r  r   r   r  r   r   r  r   r   r   r   s                r'   +test_wb1_pg_insert_uses_parameterized_queryz>TestRegisterTenant.test_wb1_pg_insert_uses_parameterized_query  sM     *^7$$X|/C/CDDD8}0 0 00} 00000} 0000000s000s00000080008000}000000000000 00000000H.v6C)C6)CCCC6)CCC6CCC)CCCCCCC 	Es   6IH?HIc                  K   t               \  }}}|j                  t        t        j                         d {    t
         t         }|j                  } ||      }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        t        j                  |            d x}}t        j                  |j!                  |            }|d   }	d}
|	|
k(  }|slt        j"                  d|fd|	|
f      t        j                  |	      t        j                  |
      d	z  }d
d|iz  }t        t        j                  |            d x}	x}}
y 7 w)Nr  r   r  r  r_   r1  r   r   r   r   r   )r   r   r   r   r   r   rH   r   r   r   r   r   r   r   r'  r(  r/   r   r)  s                 r'   test_wb2_redis_set_after_insertz2TestRegisterTenant.test_wb2_redis_set_after_insert  s(     ,
A$$X|/F/FGGG$ohZ0	""-"9--------z---z---"------9---9----------JNN956f~--~----~---~----------	 	Hs   6GGF GNrK   )rO   rP   rQ   rR   r   r  r  r]  r`  rd  rf  rh  r,   r)   r'   rY  rY    s    )[[1 1 [[N N [[9 9 [[D D [[. .r)   rY  c                  8    e Zd ZdZddZddZddZddZddZy)	TestRlmTenantModelzStory 2.06 -- BB1-BB3, WB1-WB2.c                Z   ddl m} d }||u}|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y )	Nr   	RlmTenantis notz%(py0)s is not %(py3)srm  rT  rU  r  )
core.models.schemarm  r   r   r   r   r   r   r   r   )r&   rm  r   r   rV  r   s         r'   test_bb1_import_rlm_tenantz-TestRlmTenantModel.test_bb1_import_rlm_tenant  s^    0 $$y$$$$y$$$$$$y$$$y$$$$$$$$$$r)   c                0   ddl m}  |t                     }g }|j                  }d }||u }|}|s|j                  }d}	||	k(  }
|
}|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }d	d
|iz  }|j                  |       |st	        j
                  d
fd	f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |	      dz  }dd|iz  }|j                  |       t	        j                  |d      i z  }dd|iz  }t        t	        j                  |            d x}x}x}x}x}x}x}
}	g }|j                  }d }||u }|}|s|j                  }d}	||	u }
|
}|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }d	d
|iz  }|j                  |       |st	        j
                  d|
fd||	f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |	      dz  }dd|iz  }|j                  |       t	        j                  |d      i z  }dd|iz  }t        t	        j                  |            d x}x}x}x}x}x}x}
}	y )Nr   rl  )r^   r  r   )z,%(py4)s
{%(py4)s = %(py2)s.tier
} is %(py7)stenant)r   r   r   z%(py9)sr  r   )z0%(py13)s
{%(py13)s = %(py11)s.tier
} == %(py16)s)py11py13py16z%(py18)spy18r7   zassert %(py21)spy21T)z1%(py4)s
{%(py4)s = %(py2)s.is_active
} is %(py7)s)z5%(py13)s
{%(py13)s = %(py11)s.is_active
} is %(py16)s)rq  rm  r   r_   r   r   r   r   r   r   rs   _format_boolopr   r   rf   )r&   rm  rt  r   r   r  r   r   @py_assert12@py_assert15@py_assert14r   r  @py_format17@py_format19@py_format20@py_format22s                    r'   "test_bb2_minimal_instance_defaultsz5TestRlmTenantModel.test_bb2_minimal_instance_defaults  s   0UW->v{{>d>{d">fkk>Y>kY&>>>>>{d>>>>>>v>>>v>>>{>>>d>>>>>>>kY>>>>>>f>>>f>>>k>>>Y>>>>>>>>>>>>>>CvC4C4'C6+;+;CtC+;t+CCCCC4CCCCCCvCCCvCCCCCC4CCCCCCC+;tCCCCCC6CCC6CCC+;CCCtCCCCCCCCCCCCCCr)   c                   ddl m}m} d }||u}|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}d }||u}|st        j                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y )
Nr   )rm  RlmTenantAuditrn  rp  rm  rT  rU  r  r  )core.modelsrm  r  r   r   r   r   r   r   r   r   )r&   rm  r  r   r   rV  r   s          r'   #test_bb3_import_from_models_packagez6TestRlmTenantModel.test_bb3_import_from_models_package  s    9 $$y$$$$y$$$$$$y$$$y$$$$$$$$$$%))~T))))~T))))))~)))~)))T)))))))r)   c                   ddl m} |j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d x}x}}y )
Nr   rl  r\   r   )z5%(py2)s
{%(py2)s = %(py0)s.__tablename__
} == %(py5)srm  r"  r   r   )rq  rm  __tablename__r   r   r   r   r   r   r   r   )r&   rm  r   r   r   r   r   s          r'   test_wb1_tablenamez%TestRlmTenantModel.test_wb1_tablename$  sw    0&&7-7&-7777&-777777y777y777&777-7777777r)   c                   ddl m} |j                  j                  j                  }|j
                  }d }||u}|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nr   rl  rn  )z:%(py2)s
{%(py2)s = %(py0)s.server_default
} is not %(py5)screated_colr"  r   r   )rq  rm  	__table__crd   server_defaultr   r   r   r   r   r   r   r   )r&   rm  r  r   r   r   r   r   s           r'   test_wb2_has_server_default_nowz2TestRlmTenantModel.test_wb2_has_server_default_now(  s    0))++66))55)5555)555555{555{555)5555555555r)   NrK   )	rO   rP   rQ   rR   rr  r  r  r  r  r,   r)   r'   rj  rj    s    )%D*
86r)   rj  c                      e Zd ZdZej
                  j                  dd       Zej
                  j                  dd       Zej
                  j                  dd       Z	ddZ
ej
                  j                  dd       Zy)	TestStripeWebhookHandlerzStory 2.07 -- BB1-BB3, WB1-WB2.c                  K   t               \  }}}|j                  t        t        j                         d {    dddt        t              ddi}t        d||       d {   }|d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}|d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}|d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}y 7 7 w)Nobjectcus_testr  genesis_tierr^   customermetadatacustomer.subscription.updatedstatusokr   r   r   r   r   actiontier_updatedry   )r   r   r   r   r   r>   r   r   r   r   r   r   
r&   r   r  
event_datarS  r   r   r   r   r   s
             r'   2test_bb1_subscription_updated_triggers_tier_updatezKTestStripeWebhookHandler.test_bb1_subscription_updated_triggers_tier_update5  sn    #~1$$X|/C/CDDD &$2!$X

 ++Z
 
 h'4'4''''4''''''4'''''''h1>1>1111>111111>1111111j!3^3!^3333!^333!333^3333333! 	E
s"   6G0G*+G0$G-%FG0-G0c                  K   t               \  }}}|j                  t        t        j                         d {    dddt        t              idi}t        d||       d {   }|d   }d}||k(  }|slt        j                  d|fd	||f      t        j                  |      t        j                  |      d
z  }	dd|	iz  }
t        t        j                  |
            d x}x}}|d   }d}||k(  }|slt        j                  d|fd	||f      t        j                  |      t        j                  |      d
z  }	dd|	iz  }
t        t        j                  |
            d x}x}}|d   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d
z  }	dd|	iz  }
t        t        j                  |
            d x}x}}|j                  t        t                 }|d   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d
z  }	dd|	iz  }
t        t        j                  |
            d x}x}}y 7 K7 #w)Nr  r  r^   r  customer.subscription.deletedr  r  r   r   r   r   r   r  tenant_deactivateddeactivatedTr   r   rf   F)r   r   r   r   r   r>   r   r   r   r   r   r   ro   )r&   r   r  r   r  rS  r   r   r   r   r   rx   s               r'   0test_bb2_subscription_deleted_deactivates_tenantzITestStripeWebhookHandler.test_bb2_subscription_deleted_deactivates_tenantJ  s    )^7$$X|/C/CDDD &X

 ++Z
 
 h'4'4''''4''''''4'''''''h7#77#77777#7777777#77777777m$,,$,,,,$,,,$,,,,,,,,,, s8}-;(5(5((((5((((((5(((((((' 	E
s"   6J	J*J	#J$H J	J	c                Z  K   t               \  }}}t        ddi i|       d {   }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d x}x}}y 7 w)
Nzinvoice.paidr  r  ignoredr   r   r   r   r   )r   r   r   r   r   r   r   )	r&   r   r  rS  r   r   r   r   r   s	            r'   &test_bb3_unknown_event_returns_ignoredz?TestStripeWebhookHandler.test_bb3_unknown_event_returns_ignoredb  s     #~1*XrNF
 
 h,9,9,,,,9,,,,,,9,,,,,,,
s   !B+B)BB+c                .   ddl m} |j                         D ]  \  }}|t        v }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  t              rt	        j                  t              nddz  }t	        j                  d|       d	z   d
|iz  }t        t	        j                  |            d} y)zEPRICE_TO_TIER keys must match TIER_PRICES values from billing module.r   )TIER_PRICESr   r   
lookup_keyr   r   z"Missing PRICE_TO_TIER mapping for r   r   N)core.billing.stripe_clientr  r   r   r   r   r   r   r   r   r   r   r   )r&   r  	tier_namer  r   r   r   s          r'   &test_wb1_price_to_tier_matches_billingz?TestStripeWebhookHandler.test_wb1_price_to_tier_matches_billingj  s    :%0%6%6%8 	!Iz.  :  v     I   v   "/  I "/    5ZLA    	r)   c                b  K   t               \  }}}|j                  t        t        j                         d {    dddt        t              ddi}t        d||       d {   }|d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}|j                  t               d {   }
|
j                  }t        j                  }||k(  }|st        j                  d	|fd||f      dt        j                          v st        j"                  |
      rt        j                  |
      ndt        j                  |      dt        j                          v st        j"                  t              rt        j                  t              ndt        j                  |      dz  }	dd|	iz  }t        t        j                  |            d x}x}}y 7 7 7 +w)Nr  r  r1  r  r  r  r  r  r   r   r   r   r   zL%(py2)s
{%(py2)s = %(py0)s.tier
} == %(py6)s
{%(py6)s = %(py4)s.ENTERPRISE
}r   r   r   r   r   r   r   r   r   r   r>   r   r   r   r   r   r   r   r_   r   r   r   r   r&   r   r  r  rS  r   r   r   r   r   r   r   r   r   s                 r'   *test_wb2_update_tier_called_once_per_eventzCTestStripeWebhookHandler.test_wb2_update_tier_called_once_per_eventr  sx    #~1$$X|/C/CDDD &$0!$X

 ++Z
 
 h'4'4''''4''''''4''''''',,X66}}7 7 77} 77777} 7777777x777x777}777777777777 77777777# 	E

 75   6H/H&+H/$H)%BH/H,D%H/)H/,H/NrK   )rO   rP   rQ   rR   r   r  r  r  r  r  r  r  r,   r)   r'   r  r  2  s    )[[4 4( [[) ). [[- - [[8 8r)   r  c                  l   e Zd ZdZej
                  j                  d	d       Zej
                  j                  d	d       Zej
                  j                  d	d       Z	ej
                  j                  d	d       Z
ej
                  j                  d	d       Zej
                  j                  d	d       Zy)
TestEntitlementLifecyclez/Story 2.08 -- Full lifecycle integration tests.c                  K   t               \  }}}|j                  t        t        j                         d{   }|j
                  }t        j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                  d	   }	d
}|	|u }
|
slt        j                  d|
fd|	|f      t        j                  |	      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}	x}
}|j                  t               d{   }|j
                  }t        j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j!                  t        t        j"                         d{   }|j
                  }t        j"                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                  d	   }	d}|	|u }
|
slt        j                  d|
fd|	|f      t        j                  |	      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}	x}
}|j                  t               d{   }|j
                  }t        j"                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y7 7 87 7 .w)zBRegister tenant -> get manifest -> upgrade -> verify new manifest.Nr   r   r   r   r   r   r   r   Fr   r   r   r   r   r  T)r   r   r   r   r   r_   r   r   r   r   r   r   r   r   r   r   r  r   r  s               r'   "test_register_get_update_lifecyclez;TestEntitlementLifecycle.test_register_get_update_lifecycle  s     $~1  //,:N:NOO}}4 4 44} 44444} 4444444x444x444}444444444444 44444444  /858/58888/5888/88858888888  ,,X66}}4 4 44} 44444} 4444444x444x444}444444444444 44444444  ++Hl6O6OPP}}9 9 99} 99999} 9999999x999x999}999999999999 99999999  /747/47777/4777/77747777777  ,,X66}}9 9 99} 99999} 9999999x999x999}999999999999 99999999 P
 7 Q
 7sI   6X>X2GX>=X5>E
X>X8	GX>X;D%X>5X>8X>;X>c                  K   t               \  }}}|j                  t        t        j                         d{    |j                  t               d{   }|j                  }t        j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}|j                  t        t        j                          d{    |j                  t               d{   }
|
j                  }t        j                   }||k(  }|st        j                  d|fd	||f      d
t        j                         v st        j                  |
      rt        j                  |
      nd
t        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}y7 7 7 H7 .w)zHGet manifest (cached) -> update tier -> get manifest -> verify new tier.Nr   r   m1r   r   r   r   r  m2)r   r   r   r   r   r   r_   r   r   r   r   r   r   r   r   r  r   )r&   r   r   r  r  r   r   r   r   r   r  s              r'   &test_cache_invalidation_on_tier_changez?TestEntitlementLifecycle.test_cache_invalidation_on_tier_change  s     !-
A$$X|/C/CDDD &&x00ww.,...w.....w.......r...r...w......,...,...........   <+B+BCCC &&x00ww1,111w11111w1111111r111r111w111111,111,11111111111 	E 1 	D 1sG   6K.K"K.K%E
K. K(!K.=K+>D%K.%K.(K.+K.c                  K   t               \  }}}|j                  t        t        j                         d{    ddlm}m} |j                  |j                        j                  d      }t         t         d| }d|j                  |<   |j                  t               d{   }d}	||	u }
|
slt        j                  d|
fd	||	f      t        j                  |      t        j                  |	      d
z  }dd|iz  }t!        t        j"                  |            dx}x}
}	d|j                  |<   |j                  t               d{   }d}	||	u }
|
slt        j                  d|
fd	||	f      t        j                  |      t        j                  |	      d
z  }dd|iz  }t!        t        j"                  |            dx}x}
}	y7 7 )7 w)z=Starter at 499 writes -> check passes. At 500 -> check fails.Nr   r<  r?  r@  499Tr   r   r   r   r   rA  FrB  rF  s                r'   %test_quota_check_respects_tier_limitsz>TestEntitlementLifecycle.test_quota_check_respects_tier_limits  sR     !-
A$$X|/C/CDDD/X\\*33J?$ohZq8	 (-
)$''119T91T99991T9991999T9999999 (-
)$''11:U:1U::::1U:::1:::U::::::: 	E 2 2s6   6GGA.G'G(B%GGB GGGc                b  K   t               \  }}}|j                  t        t        j                         d{    dddt        t              ddi}t        d||       d{   }|d   }d	}||k(  }|slt        j                  d
|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}|j                  t               d{   }
|
j                  }t        j                  }||k(  }|st        j                  d
|fd||f      dt        j                          v st        j"                  |
      rt        j                  |
      ndt        j                  |      dt        j                          v st        j"                  t              rt        j                  t              ndt        j                  |      dz  }	dd|	iz  }t        t        j                  |            dx}x}}y7 7 7 +w)z=Simulate subscription.updated webhook -> verify tier changed.Nr  cus_xyzr1  r  r  r  r  r  r   r   r   r   r   r  r   r   r   r   r   r  r  s                 r'   (test_stripe_webhook_triggers_tier_updatezATestEntitlementLifecycle.test_stripe_webhook_triggers_tier_update  sz     $~1$$X|/C/CDDD %$0!$X

 ++Z
 
 h'4'4''''4''''''4''''''',,X66}}7 7 77} 77777} 7777777x777x777}777777777777 77777777# 	E

 7r  c                v  K   t               \  }}}|j                  t        t        j                         d{    dddt        t              idi}t        d||       d{   }|d   }d}||u }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}t        j                  t              5  |j                  t               d{    ddd       y7 7 7 # 1 sw Y   yxY ww)z;Simulate subscription.deleted -> verify tenant deactivated.Nr  r  r^   r  r  r  Tr   r   r   r   r   )r   r   r   r   r   r>   r   r   r   r   r   r   r   r   r   r   r  s
             r'   (test_stripe_webhook_subscription_deletedzATestEntitlementLifecycle.test_stripe_webhook_subscription_deleted  s     $~1$$X|/C/CDDD %(#h-8

 ++Z
 
 m$,,$,,,,$,,,$,,,,,,,,,, ]]./ 	0%%h///	0 	0 	E
 0	0 	0sL   6D9D'*D9#D)$BD9 D-D+D-
D9)D9+D--D62D9c                <  K   t               \  }}}|j                  t        t        j                         d{    t        j                  t              5  |j                  t        t        j                         d{    ddd       y7 S7 # 1 sw Y   yxY ww)z>Register same tenant twice -> assert TenantAlreadyExistsError.Nr_  r   s      r'   (test_duplicate_registration_raises_errorzATestEntitlementLifecycle.test_duplicate_registration_raises_error  s      $~1$$X|/C/CDDD]]34 	N((<3L3LMMM	N 	N 	EM	N 	Nra  NrK   )rO   rP   rQ   rR   r   r  r  r  r  r  r  r  r  r,   r)   r'   r  r    s    9[[: :, [[2 2" [[; ;" [[8 8, [[0 0( [[N Nr)   r  c                  8    e Zd ZdZddZddZddZddZddZy)	TestContractsz(Verify contracts types used by Module 2.c                   t        t              }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               nddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}d	}t        |      }t        j                  }||k(  }|st        j                  d|fd
||f      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}x}}y )Nr   r   r   rq   r   r   r   r   r  )zM%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py8)s
{%(py8)s = %(py6)s.STARTER
}r   r   r   r   r   r.  r/  )rq   r   r   r   r   r   r   r   r   r   r   
r&   r   r   r   r   r   r   r   r2  r3  s
             r'   test_customer_tier_valuesz'TestContracts.test_customer_tier_values  s;   < %A% A%%%% A%%%%%%s%%%s%%%%%%<%%%<%%% %%%A%%%%%%%%>|I&>,*>*>>&*>>>>>&*>>>>>>>|>>>|>>>I>>>&>>>>>>,>>>,>>>*>>>>>>>>r)   c                   t        t               t        j                        }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}|j                  }d	}||k(  }|st        j                  d|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )N)r^   r_   moderater   )z4%(py2)s
{%(py2)s = %(py0)s.decay_policy
} == %(py5)smr"  r   r   r   r!  i  )z<%(py2)s
{%(py2)s = %(py0)s.max_memories_per_day
} == %(py5)s)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r&   r  r   r   r   r   r   s          r'   "test_entitlement_manifest_defaultsz0TestContracts.test_entitlement_manifest_defaults  sg   %'8L8LM~~++~++++~++++++q+++q+++~++++++++++  'C' C'''' C''''''q'''q''' '''C'''''''%%,,%,,,,%,,,,,,q,,,q,,,%,,,,,,,,,,r)   c                   t               }t        |t        j                        }t	        |      }t        |      }|j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d x}}|j                  }t        j                  }	||	k(  }|st        j                  d|fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |	      d
z  }dd|iz  }
t        t        j                  |
            d x}x}}	|j                   }|j                   }	||	k(  }|st        j                  d|fd||	f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |	      d
z  }dd|iz  }
t        t        j                  |
            d x}x}}	y )Nr   r   restoredrw   r   r   r   r  r   r   r   r   )zN%(py2)s
{%(py2)s = %(py0)s.features
} == %(py6)s
{%(py6)s = %(py4)s.features
}r   )r   r   r   r   r   r   r^   r   r   r   r   r   r   r   r   r_   r   )r&   rw   r   
serializedr  r   r   r   r   r   r   s              r'   $test_serialize_deserialize_roundtripz2TestContracts.test_serialize_deserialize_roundtrip  s   g"3(A(AB(2
(4!!(!S((((!S((((((x(((x(((!((((((S(((S(((((((}}9 9 99} 99999} 9999999x999x999}999999999999 99999999  5H$5$55 $55555 $5555555x555x555 555555H555H555$55555555r)   c                   t        t              }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               nddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}d	}t        |      }t        j                  }||k(  }|st        j                  d|fd
||f      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}x}}y )Nr   r   r   rq   r   r   r   r   working)zM%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py8)s
{%(py8)s = %(py6)s.WORKING
}r  r.  r/  )rq   r   r   r   r   r   r   r   r   r   WORKINGr  s
             r'   test_memory_tier_valuesz%TestContracts.test_memory_tier_values  s7   :#!#!####!######s###s######:###:######!########:z)$:
(:(::$(:::::$(:::::::z:::z:::):::$::::::
:::
:::(::::::::r)   c                @   t        ddd      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            d x}x}}|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            d x}x}}y )Ntestgoodbad)
input_textchosen_outputrejected_outputg      ?r   )z2%(py2)s
{%(py2)s = %(py0)s.confidence
} == %(py5)sppr"  r   r   telegram_feedback)z4%(py2)s
{%(py2)s = %(py0)s.annotator_id
} == %(py5)s)r   
confidencer   r   r   r   r   r   r   r   annotator_id)r&   r  r   r   r   r   r   s          r'   test_preference_pair_defaultsz+TestContracts.test_preference_pair_defaults  s     !

 }}##}####}######r###r###}##########5"55"55555"5555555r555r555555"55555555r)   NrK   )	rO   rP   rQ   rR   r  r  r  r  r  r,   r)   r'   r  r    s    2?-6;6r)   r  )rL   r   )CrR   
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   dataclassesr'  syspathlibr   typingr   r   r   unittest.mockr   r	   uuidr
   r   r   pathrg   r>   __file__parentcore.rlm.contractsr   r   r   r   r   r   core.rlm.entitlementr   r   r   r   r   r   r   r   r   r   core.rlm.entitlement_webhookr   r   r   TENANT_BrM  r   rT   r   r   r   r   r  r7  rY  rj  r  r  r  r,   r)   r'   <module>r     s(  ( #      
  & & *   3tH~,,33::; <    77w)# )#XV Vr *'(S (S^BD BDR0( 0(n: :B*. *.b6 6BT8 T8vpN pNn!6 !6r)   