
    mj7                    `   d dl mZ d dlZd dlmc mZ d dlZ	d dl
m
Z
mZmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZmZmZ d dlmZ d dlm Z  d dl!m"Z"  G d 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.d'd"Z/d'd#Z0d'd$Z1d'd%Z2d'd&Z3dS ))    )annotationsN)datetime	timedeltatimezone)Decimal)main)create_crypto_asset)create_initial_holding_snapshot)create_wallet)data)CoinGeckoClient
PriceQuoterefresh_crypto_prices)build_crypto_report_context)connect_memory)apply_migrationsc                  *    e Zd ZddZddd	Zddd
ZdS )MockProviderreturnNonec                "    g | _         g | _        d S N)callsbatch_callsselfs    O/home/agent/.hermes/repos/FinanceManager/tests/unit/test_crypto_price_update.py__init__zMockProvider.__init__   s    ,.
>@    CHFcoingecko_idstrcurrencyr   c                |    | j                             ||f           t          ||t          d          dd          S )N
123.456789	MockGecko2026-01-31T00:00:00+00:00)r!   r#   priceproviderprovider_timestamp)r   appendr   r   )r   r!   r#   s      r   get_crypto_pricezMockProvider.get_crypto_price   sQ    
<2333|hgVbNcNcny  Oj  k  k  k  	kr   c                v      j                             t          |          f            fd|D             S )Nc                >    i | ]}|                     |          S  )r,   ).0r!   r#   r   s     r   
<dictcomp>z2MockProvider.get_crypto_prices.<locals>.<dictcomp>   s,    nnnP\d33L(KKnnnr   )r   r+   tupler   coingecko_idsr#   s   ` `r   get_crypto_priceszMockProvider.get_crypto_prices   sF    }!5!5x @AAAnnnnn`mnnnnr   Nr   r   r    )r!   r"   r#   r"   r   r   )r#   r"   )__name__
__module____qualname__r   r,   r5   r/   r   r   r   r      sj        A A A Ak k k k ko o o o o o or   r   c            	     F   t                      } t          |            t          | dddd          }t          | ddd	          }t	          | ||t          d
          ddd           t          | ddd 	          }t	          | ||t          d          ddd           | ||fS )NzSynthetic WalletHardware Wallet	Syntheticr'   wallet_namewallet_typeplatform_providerlast_verified_atBitcoinBTCbitcoin	coin_namesymbolr!   0.01verifiedsynthetic fixtureasset_id	wallet_idquantityverification_statusnoterB   zMissing CoinMISS1)r   r   r   r	   r
   r   )connrN   btc_id
missing_ids       r   
setup_connrW       s   DTd0BPa  vA  To  p  p  pI 5W`aaaF#D6YY`agYhYh  I  Pc  vQ  R  R  R  R$T^FaefffJ#D:]deh]i]i  @J  Qd  wR  S  S  S  S##r   r   r   c                 ,   t                      \  } }}t                      }t          | |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}}|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g}||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g}||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}}|                     d|f                                          }
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         }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}}d S )"Nr    r   r)   r#   max_age_seconds   ==z5%(py2)s
{%(py2)s = %(py0)s.success_count
} == %(py5)sresultpy0py2py5assert %(py7)spy7z5%(py2)s
{%(py2)s = %(py0)s.skipped_count
} == %(py5)s)z5%(py2)s
{%(py2)s = %(py0)s.warning_count
} == %(py5)s)z3%(py2)s
{%(py2)s = %(py0)s.error_count
} == %(py5)s)rE   r    z3%(py2)s
{%(py2)s = %(py0)s.batch_calls
} == %(py5)sr)   rE   r    z-%(py2)s
{%(py2)s = %(py0)s.calls
} == %(py5)sz,SELECT * FROM crypto_prices WHERE asset_id=?)is not)z%(py0)s is not %(py3)srowra   py3assert %(py5)src   r(   r%   z%(py1)s == %(py4)spy1py4assert %(py6)spy6price_currencyr&   )rW   r   r   success_count
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationskipped_countwarning_counterror_countr   r   executefetchone)rT   rU   _r)   r_   @py_assert1@py_assert4@py_assert3@py_format6@py_format8rl   @py_assert2@py_format4@py_assert0@py_format5@py_format7s                   r   Ctest_refresh_crypto_prices_loads_active_assets_and_stores_chf_pricer   +   s^    llOD&!~~H"4(U\]^^^F$1$1$$$$$$$$$$1$$$$$$$$$$$$6$$$$$6$$$$$$$$$$1$$$$$$$$$$$$$$$$$$$$$$$$$$$$1$1$$$$$$$$$$1$$$$$$$$$$$$6$$$$$6$$$$$$$$$$1$$$$$$$$$$$$$$$$$$$$$$$$$$$$1$1$$$$$$$$$$1$$$$$$$$$$$$6$$$$$6$$$$$$$$$$1$$$$$$$$$$$$$$$$$$$$$$$$$$$""""""""""""""""""""""""6"""""6""""""""""""""""""""""""""""""""""""":$9#::#:::::::::::#:::::::::::::8:::::8::::::::::#::::::::::::::::::::::::::::>1011>11111111111>11111111111118111118111111>11111111111111111111111111111111
,,Ey
Q
Q
Z
Z
\
\C3d?3d33dw<'<'<<''''''''''<<'''''<''''<''''''''''''''''''''''''''' )E) E)))))))))) E))))) ))))E)))))))))))))))))))))))))))z?)k)?k))))))))))?k)))))?))))k)))))))))))))))))))))))))))))r   c                    t                      \  } }}t                      }t          | |dd          }t          | |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}}|                     d|f                                          }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        |          rt	          j	        |          ndt	          j	        |          t	          j	        |          dz  }dd|iz  }t          t	          j        |                    d x}x}}|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 S )Nr    r   rY   r[   r\   rf   firstr`   rd   re   secondzISELECT * FROM alerts WHERE entity_id=? AND rule_id='missing_coingecko_id'z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenalertsra   rr   rn   ru   assert %(py8)spy8occurrence_count   >=z%(py1)s >= %(py4)srq   rt   ru   )rW   r   r   r   rx   ry   rz   r{   r|   r}   r~   r   r   fetchallr   )rT   r   rV   r)   r   r   r   r   r   r   r   r   r   @py_assert5r   @py_format9r   r   s                     r   Htest_missing_coingecko_id_is_skipped_and_warned_without_duplicate_alertsr   >   s   $,,D!Z~~H!$E[\]]]E"4(U\]^^^F#!#!##########!############5#####5##########!###########################$1$1$$$$$$$$$$1$$$$$$$$$$$$6$$$$$6$$$$$$$$$$1$$$$$$$$$$$$$$$$$$$$$$$$$$$\\ehrgtuu~~  A  AFv;;!;!;!33vv;!!9'(-A-(A----------(A-----(----A-----------------------------r   c                 .   ddig } dfd	}t          ddd|| j                  }|                    d	d
          }|j        }d}t	          |          }||k    }|st          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
        |          t          j
        |          dz  }dd|iz  }	t          t          j        |	                    d x}x}x}}dg}
| |
k    }|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         }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 S )Nnr      c                    dxx         dz  cc<   d         dk    r#t           j                            | ddd d            G d d          } |            S )Nr   r[     rate limitedc                       e Zd Zd Zd Zd ZdS )Btest_429_backoff_is_used_by_provider.<locals>.opener.<locals>.Respc                    | S r   r/   r   s    r   	__enter__zLtest_429_backoff_is_used_by_provider.<locals>.opener.<locals>.Resp.__enter__U   s    r   c                    dS )NFr/   )r   argss     r   __exit__zKtest_429_backoff_is_used_by_provider.<locals>.opener.<locals>.Resp.__exit__V   s    eer   c                    dS )Ns8   {"bitcoin":{"chf":"12.34","last_updated_at":1700000000}}r/   r   s    r   readzGtest_429_backoff_is_used_by_provider.<locals>.opener.<locals>.Resp.readW   s    #^#^r   N)r8   r9   r:   r   r   r   r/   r   r   Respr   T   s+        ,,,333^^^^^r   r   urlliberror	HTTPError)urltimeoutr   r   s      r   openerz4test_429_backoff_is_used_by_provider.<locals>.openerP   s    c


a


:??,((c>4NNN	_ 	_ 	_ 	_ 	_ 	_ 	_ 	_ tvvr   r   g      ?r[   max_retriesinitial_backoff_secondsmax_backoff_secondsr   sleeperrE   r    z12.34r\   )zK%(py2)s
{%(py2)s = %(py0)s.price
} == %(py8)s
{%(py8)s = %(py4)s(%(py6)s)
}quoter   )ra   rb   rs   ru   r   zassert %(py10)spy10z%(py0)s == %(py3)ssleepsrm   ro   rc   rp   rq   rt   ru   r   )r   r+   r,   r(   r   rx   ry   rz   r{   r|   r}   r~   r   )r   r   clientr   r   r   @py_assert7r   r   @py_format11r   r   r   r   r   r   r   s                   @r   $test_429_backoff_is_used_by_providerr   L   s   !HEF      D^_hnx~  yF  G  G  GF##Iu55E;*'*''***;***********;*************5*****5******;***********'*****'******'**********************************V6V6V66V::?::r   c                    t                      \  } }t                      }t          | |dd          }t          | |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}}|j        }dg}||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}}t          j        t           j                  t%          d          z
                                  }
|                     d|
|
f           |                                  t-          j        | d          }t1          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}}t3          | d          }fd|d         D             }t5          |          }|sddt          j                    v st	          j        t4                    rt	          j	        t4                    ndt	          j	        |          t	          j	        |          dz  }t          t	          j        |                    d x}}d S ) Nr      rY   r[   r\   r^   r   r`   rd   re   )z4%(py2)s
{%(py2)s = %(py0)s.cached_count
} == %(py5)sr   ri   rj   r)   
   daysLUPDATE crypto_prices SET fetched_at=?, provider_timestamp=? WHERE asset_id=?)price_max_age_secondsc              3  2   K   | ]}|d          dk    |V  dS rH   rD   Nr/   r0   rl   s     r   	<genexpr>zNtest_fresh_cache_prevents_refetch_and_stale_price_is_marked.<locals>.<genexpr>q   0      AAs#h-5*@*@s*@*@*@*@AAr   price_qualitystalerp   rq   rt   ru   c              3  H   K   | ]}|d          dk    o|d         k    V  dS )codestale_price	entity_idNr/   r0   wrU   s     r   r   zNtest_fresh_cache_prevents_refetch_and_stale_price_is_marked.<locals>.<genexpr>t   s:      qq1qyM)Fan.Fqqqqqqr   data_quality_warnings,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyra   rb   rs   )rW   r   r   rw   rx   ry   rz   r{   r|   r}   r~   r   cached_countr   r   nowr   utcr   	isoformatr   commitr   get_crypto_overviewnextr   r   )rT   r   r)   r   r   r   r   r   r   r   oldoverviewbtcr   r   r   r   contextrU   s                     @r   ;test_fresh_cache_prevents_refetch_and_stale_price_is_markedr   c   s    llOD&!~~H!$E[_```E"4(U\`aaaF#!#!##########!############5#####5##########!############################!#!##########!############6#####6##########!###########################>1011>11111111111>11111111111118111118111111>11111111111111111111111111111111<%%	r(:(:(::
E
E
G
GCLL_begjlrastttKKMMM'DIIIH
AAhAAA
A
AC*7*7**********7*********7***************************)$dKKKGqqqqPWXoPpqqqq3qqqqqqqqqqqqqqqq3qqqqq3qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqr   c                    t                      \  } }}t          | t                      dd           t          j        |           }t          j        |           }t          j        |           }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         }|s:ddt          j
        |          iz  }t          t          j        |                    d }d |D             }t          |          }|sddt          j                    v st          j        t                    rt          j
        t                    ndt          j
        |          t          j
        |          dz  }
t          t          j        |
                    d 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         }|s:ddt          j
        |          iz  }t          t          j        |                    d }d S )Nr    r   rY   c              3  2   K   | ]}|d          dk    |V  dS r   r/   r   s     r   r   zNtest_dashboard_reads_local_prices_without_provider_api_call.<locals>.<genexpr>   r   r   latest_price_chfz123.46r\   rp   rq   rt   ru   market_value_chfassert %(py1)srr   c              3  >   K   | ]}|d          dk    |d         V  dS )rH   rD   wallet_value_chfNr/   r   s     r   r   zNtest_dashboard_reads_local_prices_without_provider_api_call.<locals>.<genexpr>   s7      VV3s8}PU?U?Us%&?U?U?U?UVVr   r   r   r   crypto_total_chfz0.00)!=)z%(py1)s != %(py4)scrypto_price_data_as_of)rW   r   r   r   r   get_crypto_by_walletget_command_center_summaryr   rx   ry   r}   r~   r   r   rz   r{   r|   )rT   rU   r   r   	by_walletsummaryr   r   r   r   r   r   @py_format2r   s                 r   ;test_dashboard_reads_local_prices_without_provider_api_callr   w   s+    llOD&!$%YZ[[[['--H)$//I-d33G
AAhAAA
A
AC!".h."h.........."h....."....h...........................!"""""""""""""""""""""""""VV)VVVV3VVVVVVVVVVVVVVVV3VVVVV3VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV%&0&0&&0000000000&&00000&0000&000000000000000000000000000,---------------------------r   c                    t                      \  } }t          |           }fd|d         D             }t          |          }|sddt          j                    v st          j        t                    rt          j        t                    ndt          j        |          t          j        |          dz  }t          t          j	        |                    d x}}t          | t                      dd           t          |           }t          d	 |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         }|s:ddt          j        |          iz  }t          t          j	        |                    d }fd|d         D             }t          |          }| }|sddt          j                    v st          j        t                    rt          j        t                    ndt          j        |          t          j        |          dz  }t          t          j	        |                    d x}x}}|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}	}d S )Nc              3  H   K   | ]}|d          dk    o|d         k    V  dS r   missing_pricer   Nr/   r   s     r   r   zYtest_crypto_report_uses_local_prices_and_improves_missing_price_status.<locals>.<genexpr>   s:      rrQqyO+H+&0Hrrrrrrr   r   r   r   r   r    r   rY   c              3  2   K   | ]}|d          dk    |V  dS r   r/   r   s     r   r   zYtest_crypto_report_uses_local_prices_and_improves_missing_price_status.<locals>.<genexpr>   s0      GGsH0F0Fs0F0F0F0FGGr   coins	price_chfr%   r\   rp   rq   rt   ru   	value_chfr   rr   c              3  H   K   | ]}|d          dk    o|d         k    V  dS r   r/   r   s     r   r   zYtest_crypto_report_uses_local_prices_and_improves_missing_price_status.<locals>.<genexpr>   s;      uuQR1V9/LAkNf4Luuuuuur   z0assert not %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}metadatalive_api_callsFis)z%(py1)s is %(py4)s)rW   r   r   rz   r{   rx   r|   r}   r~   r   r   r   r   ry   )rT   r   beforer   r   r   afterr   r   r   r   r   r   r   rU   s                 @r   Ftest_crypto_report_uses_local_prices_and_improves_missing_price_statusr     s    llOD&!(..FrrrrRXYpRqrrrr3rrrrrrrrrrrrrrrr3rrrrr3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r$%YZ[[[['--E
GGeGnGGG
G
GC{+|+|++++++++++|+++++++++|+++++++++++++++++++++++++++{uuuuV[\sVtuuuusuuuuuuuuuuuuuuuuuuusuuuuusuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu-.7%7.%7777777777.%77777.7777%77777777777777777777777777777r   c           	        |dz  }|                      dt          |                     t                      }ddlm} |dz  dz  }|                      dt          |                     |j                            d	            ||          }t          |           t          |d
ddd          }t          |ddd          }	t          ||	|t          d          ddd           |                                 |                     dd            t          g d          }
|                                j        }d}|
|k    }|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 }||v }|st#          j        d!|fd"||f          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}}d%}||v }|st#          j        d!|fd"||f          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}}d&}||v }|st#          j        d!|fd"||f          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}}|                                 d S )'NruntimeJARVIS_FINANCE_RUNTIME_DIRr   )connectr   zfinance.sqlite3JARVIS_FINANCE_DB_PATHT)parentsz
CLI Walletr<   r=   r'   r>   rC   rD   rE   rF   rI   rJ   rK   rL   z'jarvis_finance.cli.main.CoinGeckoClientc                     t                      S r   )r   )kwargss    r   <lambda>zMtest_cli_update_crypto_prices_command_uses_provider_factory.<locals>.<lambda>   s    T`TbTb r   )zupdate-crypto-pricesz--max-age-seconds0r\   r   rcrm   ro   rc   CRYPTO_PRICE_UPDATE)in)z%(py1)s in %(py3)soutrr   rn   z	updated=1z"assets_still_missing_local_price=0)setenvr"   r   jarvis_finance.storage.databaser  parentmkdirr   r   r	   r
   r   closesetattrr   
readouterrr  rx   ry   rz   r{   r|   r}   r~   r   )monkeypatchtmp_pathcapsysr  rT   r  db	file_connrN   rM   r  r  r   r   r   r   r   s                    r   ;test_cli_update_crypto_prices_command_uses_provider_factoryr'     s\   "G3S\\BBBD777777	6	-	-B/R999IOODO!!!IYi\O`t  Sn  o  o  oI"9	%^ghhhH#II`ghn`o`o  FP  Wj  }X  Y  Y  Y  YOOACbCbccc	@@@	A	AB





!CN27NNNNNNNNN2NNNNNNNNNNNN2NNNNN2NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN ' C'''''''''' C''''' '''''''''''C'''''C''''''''''''''''''''''''''';#;#;##/6/36666666666/366666/666666666663666663666666666666666666666666666JJLLLLLr   rN   r"   rG   rH   r!   c          	     r    t          | |||          }t          | ||t          d          ddd           |S )NrF   2rJ   rK   r'   rL   )r	   r
   r   )rT   rN   rG   rH   r!   rM   s         r   _add_asset_with_holdingr*     s`    "49VZfgggH#D8y[bcf[g[g  ~H  Ob  uP  Q  Q  Q  QOr   c                 L   t                      \  } }}|                     d                                          d         }t          | |ddd          }t	                      }t          | |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g}||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}	}|                     d||f                                          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 S )N,SELECT wallet_id FROM crypto_wallets LIMIT 1rN   EthereumETHethereumrF   r    r   rY   r   r\   z5%(py2)s
{%(py2)s = %(py0)s.updated_count
} == %(py5)sr_   r`   rd   re   ))rE   r/  r    rh   r)   z@SELECT COUNT(*) AS n FROM crypto_prices WHERE asset_id IN (?, ?)r   rp   rq   rt   ru   )rW   r   r   r*  r   r   updated_countrx   ry   rz   r{   r|   r}   r~   r   r   )rT   rU   r   rN   eth_idr)   r_   r   r   r   r   r   r   r   r   r   s                   r   ?test_batch_request_updates_multiple_assets_in_one_provider_callr3     s    llOD&!KLLUUWWXcdI$T9
SXgqrrrF~~H"4(U\]^^^F$1$1$$$$$$$$$$1$$$$$$$$$$$$6$$$$$6$$$$$$$$$$1$$$$$$$$$$$$$$$$$$$$$$$$$$$E$D#EE#EEEEEEEEEEE#EEEEEEEEEEEEE8EEEEE8EEEEEEEEEE#EEEEEEEEEEEEEEEEEEEEEEEEEEEE<<Z]cek\lmmvvxxy|}  C  BC  C}  BC  C  C  C  C  C  C  C  C  C  C}  BC  C  C  C  C  C}  C  C  C  C  BC  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  C  Cr   c                    t                      \  } }}|                     d                                          d         }t          | |ddd           t	          | t                      ddd	
           t                      }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g}||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}}|                     d|f                                          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 S )Nr,  rN   r-  r.  r/  rF   r    r   rD   r)   r#   rZ   only_symbolT)r)   r#   rZ   only_missingr[   r\   r0  r_   r`   rd   re   )r/  r    rh   r)   z8SELECT COUNT(*) AS n FROM crypto_prices WHERE asset_id=?r   rp   rq   rt   ru   )rW   r   r   r*  r   r   r1  rx   ry   rz   r{   r|   r}   r~   r   r   )rT   rU   r   rN   r)   r_   r   r   r   r   r   r   r   r   r   s                  r   :test_only_missing_refreshes_assets_without_any_fresh_pricer9     s-    llOD&!KLLUUWWXcdID)z%^hiiii$%Y]kpqqqq~~H"4(U\`ostttF$1$1$$$$$$$$$$1$$$$$$$$$$$$6$$$$$6$$$$$$$$$$1$$$$$$$$$$$$$$$$$$$$$$$$$$$;$:#;;#;;;;;;;;;;;#;;;;;;;;;;;;;8;;;;;8;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<RU[T]^^ggiijmnsrssnrsssssssssssnrssssssnssssrssssssssssssssssssssssssssssssr   c                    t                      \  } }}|                     d                                          d         }t          | |ddd           t	          | t                      dd	           t          j        t          j	                  t          d
          z
                                  }|                     d|||f           |                                  t                      }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g}||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}	}d S )Nr,  rN   r-  r.  r/  rF   r    r   rY   r   r   r   T)r)   r#   rZ   
only_staler[   r\   r0  r_   r`   rd   re   rg   rh   r)   )rW   r   r   r*  r   r   r   r   r   r   r   r   r   r1  rx   ry   rz   r{   r|   r}   r~   r   r   )rT   rU   r   rN   r   r)   r_   r   r   r   r   r   s               r   1test_only_stale_refreshes_only_stale_local_pricesr<     s    llOD&!KLLUUWWXcdID)z%^hiiii$%Y]^^^^<%%	r(:(:(::
E
E
G
GCLL_begjlrastttKKMMM~~H"4(U\`mqrrrF$1$1$$$$$$$$$$1$$$$$$$$$$$$6$$$$$6$$$$$$$$$$1$$$$$$$$$$$$$$$$$$$$$$$$$$$:$9#::#:::::::::::#:::::::::::::8:::::8::::::::::#::::::::::::::::::::::::::::::r   c                    t                      \  } }}|                     d                                          d         }t          | |ddd           t          | |ddd	           t	                      }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g}||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}}t	                      }
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         d         }t!          |          }d}||k    }|st          j        d|fd||f          dt          j
                    v st          j        t                     rt          j        t                     ndt          j        |          t          j        |          t          j        |          dz  }	dd|	iz  }t          t          j        |                    d x}x}x}}d S )Nr,  rN   r-  r.  r/  rF   SolanaSOLsolanar    r   r5  r[   r\   r0  symbol_resultr`   rd   re   r8  rh   r)   )r)   r#   rZ   limitlimit_result)z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} == %(py7)sr   )ra   rb   rs   re   zassert %(py9)spy9)rW   r   r   r*  r   r   r1  rx   ry   rz   r{   r|   r}   r~   r   r   r   )rT   r   rN   r)   rA  r   r   r   r   r   	provider2rC  @py_assert6r   @py_format10s                  r   2test_only_symbol_and_limit_constrain_refresh_scoperH     sm   JD!QKLLUUWWXcdID)z%^hiiiiD)x\deeee~~H)$EcdrwxxxM&+!+&!++++++++++&!++++++++++++=+++++=++++++&++++!+++++++++++++++++++++++++++;$:#;;#;;;;;;;;;;;#;;;;;;;;;;;;;8;;;;;8;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;I(	EcdlmnnnL%**%**********%************<*****<******%*******************************$Q'*03*++0q0+q0000000000+q0000000000003000003000000*0000+0000q0000000000000000000000000000000r   c                 D   t                      \  } }}|                     d||f                                          d         }t          | t	                      ddd          }|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}}|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}}|                     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||f                                          d         }
|
|k    }|st          j        d|fd|
|f          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}
}d S )Nz:SELECT COUNT(*) AS n FROM alerts WHERE entity_id IN (?, ?)r   r    r   T)r)   r#   rZ   dry_runr  )z/%(py2)s
{%(py2)s = %(py0)s.dry_run
} is %(py5)sr_   r`   rd   re   r[   r\   r0  r   )zA%(py2)s
{%(py2)s = %(py0)s.missing_local_price_count
} == %(py5)sz'SELECT COUNT(*) AS n FROM crypto_pricesrp   rq   rt   ru   )z%(py1)s == %(py3)salerts_beforer  ro   rc   )rW   r   r   r   r   rJ  rx   ry   rz   r{   r|   r}   r~   r   r1  missing_local_price_count)rT   rU   rV   rK  r_   r   r   r   r   r   r   r   r   r   r   s                  r   ,test_dry_run_does_not_write_prices_or_alertsrM     s   )||D&*LL!]`fhr_stt}}  AD  EM"4,..5bcmqrrrF>!T!>T!!!!!!!!!!>T!!!!!!!!!!!!6!!!!!6!!!!!!>!!!!T!!!!!!!!!!!!!!!!!!!!!!!!!!!$1$1$$$$$$$$$$1$$$$$$$$$$$$6$$$$$6$$$$$$$$$$1$$$$$$$$$$$$$$$$$$$$$$$$$$$+0q0+q0000000000+q0000000000006000006000000+0000q000000000000000000000000000<<ABBKKMMcRWVWWRVWWWWWWWWWWWRVWWWWWWRWWWWVWWWWWWWWWWWWWWWWWWWWWWWWWWWW<<TW]_iVjkkttvvwz{  M{  @M  M  M  M  M  M  M  M  M  M  M{  @M  M  M  M  M  M{  M  M  M  M  M  M  M  M  M  M  M  @M  M  M  M  M  M  @M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  M  Mr   c                    g } ddidfd	}t          ddd|| j                  }|                    d	d
g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g}| |k    }	|	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 |                                D             }dh}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}d S )Nr   r   r   c                j    dxx         dz  cc<   t           j                            | ddd d           )Nr   r[   r   r   r   )r   r   r   s     r   r   zUtest_rate_limit_after_retries_marks_batch_stale_and_backoff_is_capped.<locals>.opener  s6    c


a


l$$S#~tTJJJr   r   g      ?g      ?r   rE   r/  r       r\   rp   rq   rt   ru   r   r   rm   ro   rc   c                    h | ]	}|j         
S r/   )quality_status)r0   r   s     r   	<setcomp>zXtest_rate_limit_after_retries_marks_batch_stale_and_backoff_is_capped.<locals>.<setcomp>  s    >>>UE >>>r   r   r   )r   r+   r5   rx   ry   r}   r~   r   rz   r{   r|   values)r   r   r   quotesr   r   r   r   r   r   r   r   r   s               @r   Etest_rate_limit_after_retries_marks_batch_stale_and_backoff_is_cappedrV    s   F!HEK K K K K K C]ajp  {A  {H  I  I  IF%%y*&=uEEF::?::4[ 6[          6[            6     6      [                         >>fmmoo>>>K7)K>)KKKKKKKKKK>)KKKKK>KKKK)KKKKKKKKKKKKKKKKKKKKKKKKKKKKKr   c                 <    G d d          } t                      \  }}}t          | |             ddd           t          | |             ddd           |                    d|f                                          }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	        |          rt          j
        |          ndt          j
        |          t          j
        |          dz  }dd|iz  }	t          t          j        |	                    d x}x}}|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 S )Nc                      e Zd ZddZdS )Wtest_missing_local_price_alert_is_deduped_for_failed_refreshes.<locals>.MissingProviderr    c                     fd|D             S )Nc           
     :    i | ]}|t          |d dd          S )Nmissingz
not listed)rR  error_message)r   )r0   cidr#   s     r   r1   z}test_missing_local_price_alert_is_deduped_for_failed_refreshes.<locals>.MissingProvider.get_crypto_prices.<locals>.<dictcomp>  sB      I  I  IsvCC4	amnnn  I  I  Ir   r/   r3   s     `r   r5   zitest_missing_local_price_alert_is_deduped_for_failed_refreshes.<locals>.MissingProvider.get_crypto_prices  s:     I  I  I  I  {H  I  I  I  Ir   Nr7   )r8   r9   r:   r5   r/   r   r   MissingProviderrY    s.        	I 	I 	I 	I 	I 	Ir   r_  r    r   rD   r5  zOSELECT * FROM alerts WHERE entity_id=? AND rule_id='crypto_price_missing_local'r[   r\   r   r   r   r   r   r   r   r   r   r   rq   rt   ru   )rW   r   r   r   r   rx   ry   rz   r{   r|   r}   r~   r   )r_  rT   rU   r   r   r   r   r   r   r   r   r   r   s                r   >test_missing_local_price_alert_is_deduped_for_failed_refreshesr`    s   I I I I I I I I !llOD&!$):):U\]kpqqqq$):):U\]kpqqqq\\kntmvww  A  A  C  CFv;;!;!;!33vv;!!9'(-A-(A----------(A-----(----A-----------------------------r   r6   )rN   r"   rG   r"   rH   r"   r!   r"   )4
__future__r   builtinsrz   _pytest.assertion.rewrite	assertionrewriterx   urllib.errorr   r   r   r   decimalr   jarvis_finance.cli.mainr   jarvis_finance.crypto.assetsr	   jarvis_finance.crypto.holdingsr
   jarvis_finance.crypto.walletsr   jarvis_finance.dashboardr   jarvis_finance.market.providersr   r   r   'jarvis_finance.reports.crypto_inventoryr   r  r   !jarvis_finance.storage.migrationsr   r   rW   r   r   r   r   r   r  r'  r*  r3  r9  r<  rH  rM  rV  r`  r/   r   r   <module>rp     s   " " " " " "                   2 2 2 2 2 2 2 2 2 2       ( ( ( ( ( ( < < < < < < J J J J J J 7 7 7 7 7 7 ) ) ) ) ) ) ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ O O O O O O : : : : : : > > > > > >o o o o o o o o$ $ $* * * *&. . . .   .r r r r(. . . . 8 8 8 8   8   
C 
C 
C 
Ct t t t; ; ; ; 1 1 1 1"
M 
M 
M 
ML L L L". . . . . .r   