
    %i:!                        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Jr  SSKr\R                  R                  SS5        \R                  R                  SS5        \R                  R                  SS	5        \R                  R                  S
S5        \R                  R                  SS5        \R                  R                  SS5        \R                  R                  SS5        \R                  R                  SS5        SSKJr  \" 5         SSKJr  SSKJrJrJrJr  \R2                  R4                  r\R8                  R;                  \R8                  R=                  \5      S5      r S\!S\"S-  4S jr#S\!S\"SS4S jr$S\!S\S\!4S jr%S*S\&S \&4S! jjr'S"\&S\(\&   4S# jr)S$\&S%\(\&   S"\&4S& jr*\RV                  S' 5       r,S( r-S) r.g)+a5  Performance regression tests for rating recompute.

Usage:
    # Run benchmarks and save baseline:
    pytest tests/test_performance_recompute.py --benchmark-only --benchmark-json=tests/benchmark_baseline.json

    # Run benchmarks and compare against saved baseline:
    pytest tests/test_performance_recompute.py --benchmark-only --benchmark-compare=tests/benchmark_baseline.json

    # Run tests without benchmarking:
    pytest tests/test_performance_recompute.py -m "not slow"

    # Run including benchmarks:
    pytest tests/test_performance_recompute.py -v
    N)date	timedeltaELO_SCALE_Cz400.0
ELO_K_BASEz24.0INITIAL_RATINGz1500.0ENABLE_DRIVERfalseENABLE_TRAINERENABLE_ADJUSTMENTS	ENABLE_RDTAB_MOCK_MODEtrue)reload_settings)recompute_ratings)HorseRepositoryMeetingRepositoryRaceRepositoryStarterRepositoryzbenchmark_baseline.jsonkeyreturnc                    [         R                  R                  [        5      (       d  g [	        [        5       n[
        R                  " U5      nSSS5        WR                  S/ 5      nU H>  nUR                  SS5      nXP:X  d  M  UR                  S0 5      R                  SS5      s  $    g! , (       d  f       Ne= f! [
        R                  [        [        4 a     gf = f)zLoad a benchmark baseline value from JSON file if it exists.

Reads the pytest-benchmark JSON output format and finds the mean
execution time for the benchmark with the given test name.
N
benchmarksname statsmean)ospathexistsBENCHMARK_BASELINE_FILEopenjsonloadgetJSONDecodeErrorKeyError	TypeError)r   fdatar   br   s         E/root/tipsharks/tipsharks-elo-api/tests/test_performance_recompute.py_load_baseliner,   9   s     77>>122	)*a99Q<D +XXlB/
A55$D{uuWb)--fd;;   +*   (I6 s4   C B04C 	#C -C 0
B>:C C#"C#	test_namecurrent_meanc                    [        U 5      nUb  US:  a  X-  nSoCU:  oU(       d  [        R                  " SU4SX445      S[        R                  " 5       ;   d  [        R
                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      S.-  n[        R                  " SU  S	US
-  S SUS
-  S SUS-
  S-  S S3	5      S-   SU0-  n[        [        R                  " U5      5      eS=pTggg)a4  Check that the current benchmark result is within 10% of the saved baseline.

Args:
    test_name: Name of the test function (matches the "name" field in baseline JSON)
    current_mean: Current mean execution time in seconds

Raises:
    AssertionError: If current run is more than 10% slower than baseline
Nr   g?<z%(py0)s < %(py3)sslowdown_ratiopy0py3z$Performance regression detected for z: i  .2fzms vs baseline zms (   d   z.1fz% slower, limit is 10%)
>assert %(py5)spy5)
r,   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanation)r-   r.   baseliner3   @py_assert2@py_assert1@py_format4@py_format6s           r+   _check_benchmark_baselinerJ   N   s    i(H1%0 $ 	
$ 	
 	
 		
~ 	
 	
 
6		
 	
 		
~ 	
 	
 
			
~ 	
 	
 
			
 	
 	
 		
29+Rd"3'x$s6K L!#s*3//FH	
 	
 	
 		
 	
 !-    
meeting_idmeeting_datevenuec                 V    [         R                  " U UUR                  5       USS.5      $ )NH)meetingr   r   category)r   upsert	isoformat)sessionrL   rM   rN   s       r+   _create_test_meetingrV   e   s2    ##! **,		
 rK   race_numberdistancec                 l    SUS-  -   n[         R                  " U UR                  UUSSSUS S3S.5      $ )	N      mobilepacez2025-05-06T02dz:00:00+12:00)rW   rX   
start_typegaitadvertised_start_string)r   rS   id)rU   rQ   rW   rX   hours        r+   _create_test_racerd   q   sM    b !D  

& ")4T#Jl'K	

 
rK   countc                     / n[        U5       H3  nSU-   n[        R                  " XSU 35        UR                  U5        M5     U$ )N(#  Horse_)ranger   rS   append)rU   re   	horse_idsihorse_ids        r+   _create_test_horsesrn      sJ    I5\!8wF1#,?"  rK   race_idrk   c                     SSK nUR                  U[        U[        U5      5      5      n[	        US5       H.  u  pg[
        R                  " U USUS-
   3USUS-
   3UUS.US9  M0     g)z;Create test starters with sequential placings (1 = winner).r   Nr8   rh   rg   )r   rm   
horse_namerunner_numberbarrier)placing)randomsampleminlen	enumerater   rS   )rU   ro   rk   re   ru   selectedrl   rm   s           r+   _create_test_startersr{      sx    }}YE3y>(BCH 1-   D 12$ &x$&78!" 	
 .rK   c              #     #    SnSnSnSn[        SSS5      n/ SQn[        X5      nU R                  5         [        U5       H  nU[	        US-  S	9-   n	[        U S
U 3XU[        U5      -     5      n
U R                  5         [        U5       H?  n[        X
US-   SUS-  -   5      nU R                  5         [        XR                  Xs5        MA     M     U R                  5         UnU[	        US-  S	9-   nX4v   g7f)zCreate 75 races with starters for benchmark.

Uses the same db_session as the test, so data is visible.
All changes are rolled back after the test via db_session fixture.
      rZ   2   i  r8   )AucklandChristchurch
WellingtonHamiltonDunedin   )daysperf_meeting_  r9   N)
r   rn   flushri   r   rV   rx   rd   r{   rb   )
db_sessionnum_meetingsraces_per_meetinghorses_per_racetotal_horses	base_datevenuesrk   mrM   rQ   rrace	date_fromdate_tos                  r+   fixture_races_datar      s     LOLT1a INF $J=I <  9!a%#88&-s+\!c&k/;R
 	()A$Z!a%SAQRD!*ggyR * ! I))9::G

s   C:C<c                 T   Uu  p4U " [         XU5      nSoeU:  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      S.-  n[        R                  " S5      S-   SU0-  n	[        [        R                  " U	5      5      eS	=pv[        U S
5      (       a:  U R                  b,  U R                  R                  S5      n
U
b  [        SU
5        g	g	g	g	)a3  Benchmark recompute_ratings on a fixed dataset of ~75 races.

This test uses pytest-benchmark to measure execution time. The
benchmark is run multiple times and statistics are collected.

After the benchmark runs, compares the result against a saved
baseline if one exists in tests/benchmark_baseline.json.
r   >z%(py0)s > %(py3)sresultr4   0recompute_ratings should create rating snapshotsr:   r;   Nr   r   test_recompute_performance)r   r<   r=   r>   r?   r@   rA   rB   rC   rD   hasattrr   r$   rJ   )	benchmarkr   r   r   r   r   rF   rG   rH   rI   mean_vals              r+   r   r      s     ,I(*IFIA:IIII6IIIIII6IIII6IIIAIIIIIIIIIII y'""y'B??&&v.%&BHM   (C"rK   c                    Uu  p#[         R                  " 5       n[        XU5      n[         R                  " 5       U-
  nSouU:  o(       d  [        R                  " SU4SXW45      S[
        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      S.-  n	[        R                  " S5      S-   SU	0-  n
[        [        R                  " U
5      5      eS	=pS
nXg:  o(       d  [        R                  " SU4SXg45      S[
        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      S.-  n	[        R                  " SUS S35      S-   SU	0-  n
[        [        R                  " U
5      5      eS	=pg	)zAssert recompute completes within a reasonable time threshold.

This test runs recompute once and measures wall-clock time.
It serves as a quick sanity check that the operation stays
under the 5-second threshold for 50-100 races.
r   r   r   r   r4   r   r:   r;   Ng      @r0   r2   elapsedzRecompute took r7   z#s, expected < 5.0s for 50-100 races)timeperf_counterr   r<   r=   r>   r?   r@   rA   rB   rC   rD   )r   r   r   r   startr   r   rF   rG   rH   rI   s              r+   !test_recompute_baseline_thresholdr      ss    ,IEzg>F!E)GIA:IIII6IIIIII6IIII6IIIAIIIIIIIIIIIJJ J8I8IJJ JCI6J J1I1IJJ J@I	JJ J@I	JJ J8I8IJ	%HIJ J J6I6IJ JrK   )r   )/__doc__builtinsr>   _pytest.assertion.rewrite	assertionrewriter<   r"   r   r   datetimer   r   pytestenviron
setdefaultpackages.core.common.settingsr   packages.core.ratings.recomputer   "packages.core.storage.repositoriesr   r   r   r   markslow
pytestmarkr   joindirname__file__r    strfloatr,   rJ   rV   intrd   listrn   r{   fixturer   r   r    rK   r+   <module>r      s      	  $  

  mW - 

  lF + 

  & 1 

  ow / 

  & 0 

  *G 4 

  k7 + 

  ov . :   =  [[
'',,GGOOH8   *
 
E 
d 
.	c 	 	c 	S C  S	 
C 
DI 
c 
. $ $XN,JrK   