
    iO                     X   S r SSKrSSKJs  Jr  SSKrSSKrSSK	r	SSK
Jr  SSKrSSKJrJrJr  \" \5      R%                  5       R&                  R&                  S-  S-  r\R&                  R&                  rS\S-  4S jr\R0                  " S	S
9S\4S j5       r\R0                  " S	S
9S\4S j5       r\R0                  " SS
9S 5       r\R0                  " SS
9S\S\\\4   4S j5       rS\\   S\\\4   S\R>                  4S jr \RB                  RD                   " S S5      5       r#g)a4  Tests for Alembic migrations.

Verifies that migrations can upgrade to head and downgrade to base
without errors, and that the schema after upgrade matches the
SQLAlchemy models.

These tests require a PostgreSQL instance and the TEST_DATABASE_URL
environment variable to be set. They are skipped otherwise.
    N)Path)create_engineinspecttextinfrastructurezalembic.inireturnc                  @    [         R                  R                  S5      $ )zGet the test database URL from environment.

Returns None if TEST_DATABASE_URL is not set. This ensures the test
only runs against an explicitly configured test database, preventing
accidental use of the production database.
TEST_DATABASE_URL)osenvironget     :/root/tipsharks/tipsharks-elo-api/tests/test_migrations.pyget_test_db_urlr      s     ::>>-..r   module)scopec                  L    [        5       n U c  [        R                  " S5        U $ )z9Return the test database URL, skipping if not configured.u<   TEST_DATABASE_URL not set — requires a PostgreSQL database)r   pytestskip)urls    r   test_db_urlr   &   s#     
C
{RSJr   r   c              #   J   #    [        U 5      nUv   UR                  5         g7f)zSQLAlchemy engine connected to the test database.

Note: DDL-heavy fixtures (``clean_database``) use ``AUTOCOMMIT``
isolation on individual connections to work around PostgreSQL's
requirement that DROP/CREATE SCHEMA run outside a transaction.
N)r   dispose)r   engines     r   r   r   /   s       ;'F
L
NNs   !#functionc              #   "  #    U R                  5        nUR                  SS9   UR                  [        S5      5        UR                  [        S5      5        SSS5        SSS5        Sv   g! , (       d  f       N= f! , (       d  f       N$= f7f)z<Drop and recreate the public schema for a fully clean state.
AUTOCOMMIT)isolation_levelz$DROP SCHEMA IF EXISTS public CASCADEzCREATE SCHEMA publicN)connectexecution_optionsexecuter   )r   conns     r   clean_databaser$   <   sj      
	T##L#ALLDEFLL456 B 
 
 BA 
	s3   BA>5A-A> B-
A;	7A>>
BBc                 n    [         R                  R                  5       nXS'   [        [        5      US'   U$ )zEnvironment variables for Alembic subprocess.

Overrides ``DATABASE_URL`` so that Alembic connects to the test
database rather than the one from ``.env`` or the conftest default.
DATABASE_URLALEMBIC_CONFIG)r   r   copystrALEMBIC_INI)r   envs     r   alembic_envr,   F   s1     **//
C%,CJr   commandr,   c           	      ~    [         R                  " [        R                  SSS[	        [
        5      /U Q[        USSS9$ )zRun an Alembic command and return the result.

Painless helper that embeds the config-file and working-directory
flags so every call site doesn't need to repeat them.
z-malembicz-cT)cwdr+   capture_outputr   )
subprocessrunsys
executabler)   r*   PROJECT_DIR)r-   r,   s     r   _run_alembicr7   X   sJ     >>NN	
 	
  r   c                   *    \ rS rSrSrS rS rS rSrg)TestAlembicMigrationsv   z?Test that Alembic migrations can upgrade and downgrade cleanly.c                 J   [        SS/U5      nUR                  nSoeU:H  ow(       d  [        R                  " SU4SXV45      S[        R
                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " SUR                   S	UR                   S
UR                   35      S-   SU0-  n	[        [        R                  " U	5      5      eS=n=pvg)z'Applying all migrations should succeed.upgradeheadr   ==z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)sresultpy0py2py5"alembic upgrade head failed (exit )
--- stdout ---

--- stderr ---

>assert %(py7)spy7N)r7   
returncode
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgstdoutstderrAssertionError_format_explanation)
selfr   r$   r,   rA   @py_assert1@py_assert4@py_assert3@py_format6@py_format8s
             r   test_upgrade_head'TestAlembicMigrations.test_upgrade_headz   s   y&1;?   	
A 	
A% 	
 	
 		
  	
 	
 
6		
 	
 		
v 	
 	
 
			
v 	
 	
 
			
  	
 	
 
			
A 	
 	
 		
01B1B0C D%}}o .%}}o/	
 	
 	
 		
 	
 	
r   c                    [        SS/U5      nUR                  nSoeU:H  ow(       d  [        R                  " SU4SXV45      S[        R
                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " SUR                   S	UR                   S
UR                   35      S-   SU0-  n	[        [        R                  " U	5      5      eS=n=pv[        SS/U5      n
U
R                  nSoeU:g  ow(       d  [        R                  " SU4SXV45      S[        R
                  " 5       ;   d  [        R                  " U
5      (       a  [        R                  " U
5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " SU
R                   35      S-   SU0-  n	[        [        R                  " U	5      5      eS=n=pv/ nSnU
R                  nX;   ofo(       a  SnU
R                  nX;   nUnU(       Gd  [        R                  " SU4SX45      [        R                  " U5      S[        R
                  " 5       ;   d  [        R                  " U
5      (       a  [        R                  " U
5      OS[        R                  " U5      S.-  n	SSU	0-  nUR                  U5        U(       a  [        R                  " SW4SWW45      [        R                  " U5      S[        R
                  " 5       ;   d  [        R                  " U
5      (       a  [        R                  " U
5      OS[        R                  " U5      S.-  nSSU0-  nUR                  U5        [        R                  " US5      0 -  n[        R                  " SU
R                   S	U
R                   S
U
R                   35      S -   S!U0-  n[        [        R                  " U5      5      eS=n=n=n=n=n=n=nng)"a  After upgrading, roll back as far as possible.

Note: The ``20260106_0001_tab_api_migration`` raises ``NotImplementedError``
in its downgrade because TAB API schema restructuring is not reversable.
This test verifies that all reversable migrations downgrade cleanly.
r<   r=   r   r>   r@   	result_uprB   rF   rG   rH   rI   rJ   N	downgradebase)!=)z2%(py2)s
{%(py2)s = %(py0)s.returncode
} != %(py5)sresult_downul   Downgrade unexpectedly succeeded — expected NotImplementedError from the TAB API migration
--- stdout ---
NotImplementedErrorzDowngrade from TAB API schema)in)z.%(py3)s in %(py7)s
{%(py7)s = %(py5)s.stderr
})py3rE   rJ   z%(py9)spy9)z2%(py12)s in %(py16)s
{%(py16)s = %(py14)s.stderr
})py12py14py16z%(py18)spy18z#Unexpected downgrade failure (exit z
>assert %(py21)spy21)r7   rK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   append_format_boolop)rW   r   r$   r,   r`   rX   rY   rZ   r[   r\   rd   @py_assert2@py_assert6@py_assert0@py_assert11@py_assert15@py_assert13@py_format10@py_format17@py_format19@py_format20@py_format22s                         r   test_downgrade_base)TestAlembicMigrations.test_downgrade_base   s"    !)V!4kB	## 	
q 	
q( 	
 	
 		
# 	
 	
 
6		
 	
 		
y 	
 	
 
			
y 	
 	
 
			
# 	
 	
 
			
q 	
 	
 		
01E1E0F G(//0 1(//02	
 	
 	
 		
 	
 #K#8+F%% 	
 	
* 	
 	
 		
% 	
 	
 
6		
 	
 		
{ 	
 	
 
			
{ 	
 	
 
			
% 	
 	
 
			
 	
 	
 		
*1124	
 	
 	
 		
 	

	
!	
%0%7%7	
!7	
/	
3>3E3E	
/E	
 	
 	
!	
 	
 
		
!	
 	
 
6	
 	
 	
%0	
 	
 
		
%0	
 	
 
		
%7	
 	
 	
 
6	
 
	
 	
 	
/3E	
 	
 
		
/	
 	
 
6	
 	
 	
3>	
 	
 
		
3>	
 	
 
		
3E	
 	
 	
 
6	
 
	
 	
 	
 	
 2+2H2H1I J*112 3*1124		
 	
 	
 	
 	
 	
 	
r   c                    [        SS/U5      nUR                  nSoeU:H  ow(       d  [        R                  " SU4SXV45      S[        R
                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  n[        R                  " SUR                   S	UR                   S
UR                   35      S-   SU0-  n	[        [        R                  " U	5      5      eS=n=pvSSKJn
  [        U5      n[!        UR#                  5       5      nUR%                  S5        S1n[!        U
R&                  R(                  R+                  5       5      U-
  nX-
  nU(       + oU(       d  [        R                  " S[-        U5       35      S-   SS[        R
                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS0-  n[        [        R                  " U5      5      eSnX-
  nU(       a#  [.        R0                  " S[-        U5       35        gg)z?Every SQLAlchemy model table should exist after a full upgrade.r<   r=   r   r>   r@   rA   rB   rF   rG   rH   rI   rJ   N)Basealembic_versionprediction_historyzZTables defined in SQLAlchemy models but missing from the database after a full migration: z
>assert not %(py0)srC   missingzADatabase contains extra tables not defined in SQLAlchemy models: )r7   rK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   packages.core.storage.modelsr~   r   setget_table_namesdiscardmetadatatableskeyssortedr   r   )rW   r   r$   r,   rA   rX   rY   rZ   r[   r\   r~   	inspector	db_tables_MODELS_WITHOUT_MIGRATIONSmodel_tablesr   @py_format2extras                     r    test_schema_parity_after_upgrade6TestAlembicMigrations.test_schema_parity_after_upgrade   s;    y&1;?   	
A 	
A% 	
 	
 		
  	
 	
 
6		
 	
 		
v 	
 	
 
			
v 	
 	
 
			
  	
 	
 
			
A 	
 	
 		
01B1B0C D%}}o .%}}o/	
 	
 	
 		
 	
 	6FO		1134	 	+,
 !&
" 4==//4467:TT*{ 	
{ 	
 	
44:7O3DF	
 	
 
6	
 	
 	
7 	
 	
 
		
7 	
 	
 	
 	
 	

 (KK&&,Um_6 r   r   N)	__name__
__module____qualname____firstlineno____doc__r]   r{   r   __static_attributes__r   r   r   r9   r9   v   s    I
 
D*r   r9   )$r   builtinsrN   _pytest.assertion.rewrite	assertionrewriterL   r   r2   r4   pathlibr   r   
sqlalchemyr   r   r   __file__resolveparentr*   r6   r)   r   fixturer   r   r$   dictr,   listCompletedProcessr7   markintegrationr9   r   r   r   <module>r      s^    	  
   3 38n$$&--447GG-W  ''/t / hS    h	 	  	 j!
 "
 j!	S 	T#s(^ 	 "	"#Yc3h   < X X Xr   