Skip to main content
Glama

URL Reputation and Validity Checker

by prismon
test_cache.cpython-313-pytest-8.3.5.pyc33.1 kB
� ��7h+���SrSSKrSSKJs Jr SSKrSSKJ r J r J r J r SSK J r SSKrSSKJr SSKJr "SS5rg) zUnit tests for cache.py�N)�Mock� AsyncMock�patch� MagicMock)�datetime)�Redis)� CacheManagerc���\rSrSrSr\R S5r\R S5r\RRS5r \RRS5r \RRS5r \RRS5r\RRS 5r\RRS 5rS rS r\RRS 5r\RRS5r\RRS5r\RRS5r\RRS5r\RRS5r\RRS5r\RRS5r\RRS5r\RRS5r\RRS5r\RRS5r\RRS5r\RRS5r Sr!g)�TestCacheManager� zTest suite for CacheManager.c���[[S9n[SS9Ul[SS9Ul[SS9Ul[SS9Ul[/S9Ul[5UlU$)zCreate a mock Redis client.)�specT�� return_valueN�)rr�ping�get�setex�delete�keys�close)�self�mocks �G/home/josh/Projects/reputation-and-validity-checker/tests/test_cache.py� mock_redis�TestCacheManager.mock_redissX���e�$���4�0�� ��$�/����D�1�� ��Q�/�� ��2�.�� ��[�� �� �c�# �[5nU7v� UR(aUR5IShv�N ggN7f)zCreate a CacheManager instance.N)r �redis� disconnect)r�managers r� cache_manager�TestCacheManager.cache_managers4����.��� � �=�=��$�$�&� &� &� � &�s �4?�=�?c��# �[5nURnSo2U:HoD(d�[R"SU4SX#45S[R "5;d[R "U5(a[R"U5OS[R"U5[R"U5S.-nSSU0-n[[R"U55eS=n=pCURnSo2ULoD(d�[R"S U4S X#45S[R "5;d[R "U5(a[R"U5OS[R"U5[R"U5S.-nSSU0-n[[R"U55eS=n=pCURnS o2U:HoD(d�[R"SU4S X#45S[R "5;d[R "U5(a[R"U5OS[R"U5[R"U5S.-nSSU0-n[[R"U55eS=n=pCURnS o2U:HoD(d�[R"SU4SX#45S[R "5;d[R "U5(a[R"U5OS[R"U5[R"U5S.-nSSU0-n[[R"U55eS=n=pCURnSo2U:HoD(d�[R"SU4SX#45S[R "5;d[R "U5(a[R"U5OS[R"U5[R"U5S.-nSSU0-n[[R"U55eS=n=pCg7f)z!Test CacheManager initialization.zredis://localhost:6379��==�z1%(py2)s {%(py2)s = %(py0)s.redis_url } == %(py5)sr!��py0�py2�py5�assert %(py7)s�py7N��is�z-%(py2)s {%(py2)s = %(py0)s.redis } is %(py5)s�Q)z1%(py2)s {%(py2)s = %(py0)s.ttl_valid } == %(py5)s�)z3%(py2)s {%(py2)s = %(py0)s.ttl_invalid } == %(py5)s�: )z3%(py2)s {%(py2)s = %(py0)s.ttl_history } == %(py5)s)r � redis_url� @pytest_ar�_call_reprcompare� @py_builtins�locals�_should_repr_global_name� _saferepr�AssertionError�_format_explanationr� ttl_valid� ttl_invalid� ttl_history�rr!� @py_assert1� @py_assert4� @py_assert3� @py_format6� @py_format8s r� test_init�TestCacheManager.test_init#sL����.��� � �<�$<�<�$<�<�<�<�<�<� �<�<�<�<�<�<�w�<�<�<�<�w�<�<�<� �<�<�<�$<�<�<�<�<�<�<�<��}�}�$��$��$�$�$�$�$�}�$�$�$�$�$�$�w�$�$�$�$�w�$�$�$�}�$�$�$��$�$�$�$�$�$�$�� � �)�E�)�E�)�)�)�)�)� �)�)�)�)�)�)�w�)�)�)�)�w�)�)�)� �)�)�)�E�)�)�)�)�)�)�)��"�"�*�d�*�d�*�*�*�*�*�"�*�*�*�*�*�*�w�*�*�*�*�w�*�*�*�"�*�*�*�d�*�*�*�*�*�*�*��"�"�,�f�,�f�,�,�,�,�,�"�,�,�,�,�,�,�w�,�,�,�,�w�,�,�,�"�,�,�,�f�,�,�,�,�,�,�,�s�P>Qc���# �[SS9nURnSo2U:HoD(d�[R"SU4SX#45S[R "5;d[R "U5(a[R"U5OS[R"U5[R"U5S.-nSSU0-n[[R"U55eS =n=pCg 7f) z7Test CacheManager initialization with custom Redis URL.zredis://custom:6380)r4r%r'r!r(r,r-N) r r4r5r6r7r8r9r:r;r<r@s r�test_init_with_custom_url�*TestCacheManager.test_init_with_custom_url-s�����)>�?��� � �9�$9�9�$9�9�9�9�9�9� �9�9�9�9�9�9�w�9�9�9�9�w�9�9�9� �9�9�9�$9�9�9�9�9�9�9�9�s�C"C$c��|# �[SUS9 [5nUR5IShv�N URnSoCULoU(d�[R "SU4SX445S[ R"5;d[R"U5(a[R"U5OS[R"U5[R"U5S.-nSS U0-n[[R"U55eS=n=pTURR5 SSS5 gN�!,(df  g=f7f) z!Test successful Redis connection.�+url_reputation_checker.cache.Redis.from_urlrN��is not�z1%(py2)s {%(py2)s = %(py0)s.redis } is not %(py5)sr!r(r,r-)rr �connectrr5r6r7r8r9r:r;r<r�assert_called_once�rrr!rArBrCrDrEs r�test_connect_success�%TestCacheManager.test_connect_success3s�����@�z� Z�"�n�G��/�/�#� #� #��=�=� ,�� ,��,� ,� ,� ,� ,�=� ,� ,� ,� ,� ,� ,�7� ,� ,� ,� ,�7� ,� ,� ,�=� ,� ,� ,�� ,� ,� ,� ,� ,� ,� ,� �O�O� .� .� 0� [� Z� #�[� Z�s-� D<�D+�D)�C4D+� D<�)D+�+ D9�5D<c��# �[5n[S5URl[ SUS9 [ 5nUR 5IShv�N URnSoCULoU(d�[R"SU4SX445S[R"5;d[R"U5(a[R"U5OS[R"U5[R"U5S.-nS S U0-n[[R"U55eS=n=pTSSS5 gN�!,(df  g=f7f) zTest Redis connection failure.zConnection failedrLrNr.r0r!r(r,r-)r� Exceptionr� side_effectrr rPrr5r6r7r8r9r:r;r<rRs r�test_connect_failure�%TestCacheManager.test_connect_failure=s�����[� �&/�0C�&D� ���#� �@�z� Z�"�n�G��/�/�#� #� #��=�=� (�D� (�D�(� (� (� (� (�=� (� (� (� (� (� (�7� (� (� (� (�7� (� (� (�=� (� (� (�D� (� (� (� (� (� (� (� [� Z� #�[� Z�s/�/E�D5�D3�CD5�* E�3D5�5 E�?Ec���# �[SUS9 [5nURnSoCULoU(d�[R"SU4SX445S[ R "5;d[R"U5(a[R"U5OS[R"U5[R"U5S.-nSS U0-n[[R"U55eS=n=pTUR5IShv�N URnSoCULoU(d�[R"S U4S X445S[ R "5;d[R"U5(a[R"U5OS[R"U5[R"U5S.-nSS U0-n[[R"U55eS=n=pTSSS5 gN�!,(df  g=f7f) zTest _ensure_connected method.rLrNr.r0r!r(r,r-rMrO) rr rr5r6r7r8r9r:r;r<�_ensure_connectedrRs r�test_ensure_connected�&TestCacheManager.test_ensure_connectedIs ����@�z� Z�"�n�G��=�=� (�D� (�D�(� (� (� (� (�=� (� (� (� (� (� (�7� (� (� (� (�7� (� (� (�=� (� (� (�D� (� (� (� (� (� (� (��+�+�-� -� -��=�=� ,�� ,��,� ,� ,� ,� ,�=� ,� ,� ,� ,� ,� ,�7� ,� ,� ,� ,�7� ,� ,� ,�=� ,� ,� ,�� ,� ,� ,� ,� ,� ,� ,� [� Z� .� [� Z�s0� G8�C4G'�G%�CG'� G8�%G'�' G5�1G8c��# �[5nXlUR5IShv�N URR 5 gN7f)zTest disconnecting from Redis.N)r rr rrQ)rrr!s r�test_disconnect� TestCacheManager.test_disconnectSs<����.��"� �� � �"�"�"����+�+�-� #�s�$A�A� Ac��URSS5nSo2U:HoD(d�[R"SU4SX#45S[R"5;d[R "U5(a[R "U5OS[R "U5S.-nSS U0-n[[R"U55eS =pCg ) z0Test cache key generation for short identifiers.� validation�https://example.com�-url_reputation:validation:https://example.comr%)z%(py0)s == %(py3)s�key�r)�py3�assert %(py5)sr+N) �_get_cache_keyr5r6r7r8r9r:r;r<)rr"re� @py_assert2rA� @py_format4rDs r�test_get_cache_key_short�)TestCacheManager.test_get_cache_key_short\sr���*�*�<�9N�O��E�E�E�E�E�E�E�E�s�E�E�E�E�E�E�s�E�E�E�E�s�E�E�E�E�E�E�E�E�E�E�Erc ��SnURSU5nURnSoT"U5of(d�SS[R"5;d[R "U5(a[R "U5OS[R "U5[R "U5[R "U5S.-n[[R"U55eS=n=pV[U5nSo�U-n [U 5o�U :o�(Gd�[R"SU 4S X�45S [R"5;d[R "[5(a[R "[5OS S[R"5;d[R "U5(a[R "U5OS[R "U5S [R"5;d[R "[5(a[R "[5OS [R "U 5S [R"5;d[R "U5(a[R "U5OS [R "U 5S .-n S SU 0-n[[R"U55eS=n=n =n =p�g)z/Test cache key generation for long identifiers.z�https://example.com/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarbzurl_reputation:validation:zLassert %(py6)s {%(py6)s = %(py2)s {%(py2)s = %(py0)s.startswith }(%(py4)s) }re)r)r*�py4�py6N)�<)z[%(py3)s {%(py3)s = %(py0)s(%(py1)s) } < %(py11)s {%(py11)s = %(py5)s((%(py7)s + %(py8)s)) }�len�long_url)r)�py1rgr+r-�py8�py11zassert %(py13)s�py13) ri� startswithr7r8r5r9r:r;r<rrr6)rr"rsrerArC� @py_assert5� @py_format7rj� @py_assert6� @py_assert9� @py_assert10rB� @py_format12� @py_format14s r�test_get_cache_key_long�(TestCacheManager.test_get_cache_key_longas���5���*�*�<��B���~�~�;�:�;�~�:�;�;�;�;�;�;�;�;�;�s�;�;�;�;�s�;�;�;�~�;�;�;�:�;�;�;�;�;�;�;�;�;�;��3�x�F�:�F�X�E�F�#�E�F�F�F�F�F�F�F�F�x�F�F�F�F�F�F�s�F�F�F�F�s�F�F�F�F�F�F�3�F�F�F�F�3�F�F�F�x�F�F�F�F�F�F�#�F�F�F�F�#�F�F�F�:�F�F�F�F�F�F�X�F�F�F�F�X�F�F�F�F�F�F�F�F�F�F�F�Frc���# �SSSS.n[R"U5R5URlX!lUR S5IShv�N nXC:HoU(d�[R"SU4SXC45S[R"5;d[R"U5(a[R"U5OSS [R"5;d[R"U5(a[R"U5OS S .-nS S U0-n[[R"U55eSnURR5 gGN7f) z&Test getting cached validation result.rcT����url�is_valid� status_codeNr%�z%(py0)s == %(py2)s�result� cached_data�r)r*�assert %(py4)sro)�json�dumps�encoderrr�get_validation_resultr5r6r7r8r9r:r;r<rQ�rr"rr�r�rA� @py_format3� @py_format5s r�$test_get_validation_result_cache_hit�5TestCacheManager.test_get_validation_result_cache_hitjs����)��� � � '+�j�j��&=�&D�&D�&F� ���#�(��$�:�:�;P�Q�Q���$�$�$�$�$�v�$�$�$�$�$�$�v�$�$�$�$�v�$�$�$�$�$�$��$�$�$�$��$�$�$�$�$�$�$����)�)�+�R�s�AE �E�DE c���# �SURlX!lURS5IShv�N nSoCULoU(d�[R "SU4SX445S[ R"5;d[R"U5(a[R"U5OS[R"U5S.-nSSU0-n[[R"U55eS=pTgN�7f) z&Test cache miss for validation result.Nrcr.�z%(py0)s is %(py3)sr�rfrhr+) rrrr�r5r6r7r8r9r:r;r<)rr"rr�rjrArkrDs r�%test_get_validation_result_cache_miss�6TestCacheManager.test_get_validation_result_cache_misszs����'+� ���#�(��$�:�:�;P�Q�Q�����~�����v�������v�����v������������R�s�,C)�C'�B9C)c��# �SUlURS5IShv�N nSo2ULoD(d�[R"SU4SX#45S[R "5;d[R "U5(a[R"U5OS[R"U5S.-nSSU0-n[[R"U55eS=pCgN�7f) z;Test getting validation result when Redis is not available.Nrcr.r�r�rfrhr+) rr�r5r6r7r8r9r:r;r<)rr"r�rjrArkrDs r�#test_get_validation_result_no_redis�4TestCacheManager.test_get_validation_result_no_redis�s����#� ��$�:�:�;P�Q�Q�����~�����v�������v�����v������������R�s�C�C�B9Cc��p# �X!lSSSS.nURSUSS9IShv�N URR5 URRSnUSnSoeU:How(do[ R "S U4S XV45[ R"U5[ R"U5S .-nS S U0-n [[ R"U 55eS=n=pvUSnSoeU:How(do[ R "S U4S XV45[ R"U5[ R"U5S .-nS S U0-n [[ R"U 55eS=n=pv[R"US5n SoUU ;ow(d�[ R "SU4SXZ45[ R"U5S[R"5;d[ R"U 5(a[ R"U 5OSS.-n SSU 0-n [[ R"U 55eS=pWgGN7f)z+Test caching a valid URL validation result.rcTr�r��r�Nrrdr%�z%(py1)s == %(py4)s�rtro�assert %(py6)srprr1�� cached_at)�in)z%(py1)s in %(py3)s�data)rtrgrhr+)r�set_validation_resultrrQ� call_argsr5r6r:r;r<r��loadsr7r8r9) rr"rr��args� @py_assert0rCrjr�rzr�rkrDs r� test_set_validation_result_valid�1TestCacheManager.test_set_validation_result_valid�sx���)��)��� �� �1�1�2G��Z^�1�_�_�_����+�+�-����)�)�!�,���A�w�I�I�I�I�I�I�I�I�I�w�I�I�I�w�I�I�I�I�I�I�I�I�I�I�I��A�w��%��%������w����w����%���������z�z�$�q�'�"���"�d�"�"�"�"�"�{�"�"�"�{�"�"�"�"�"�"�d�"�"�"�"�d�"�"�"�"�"�"�"� `�s�!H6�H3�HH6c���# �X!lSSS.nURSUSS9IShv�N URR5 URRSnUSnSoeU:How(do[ R "S U4S XV45[ R"U5[ R"U5S .-nS S U0-n [[ R"U 55eS=n=pvgN�7f)z.Test caching an invalid URL validation result.zhttps://invalid.comF)r�r�r�Nrrr2r%r�r�r�rp) rr�rrQr�r5r6r:r;r<) rr"rr�r�r�rCrjr�rzs r�"test_set_validation_result_invalid�3TestCacheManager.test_set_validation_result_invalid�s����)��)�� �� �1�1�2G��Z_�1�`�`�`����+�+�-����)�)�!�,���A�w��$��$������w����w����$�������� a�s� C"�C �B>C"c��T# �SUlURS0S5IShv�N gN7f)z;Test setting validation result when Redis is not available.NrcT)rr�)rr"s r�#test_set_validation_result_no_redis�4TestCacheManager.test_set_validation_result_no_redis�s*���#� ���1�1�2G��T�R�R�R�s �(�&�(c��# �SSSS.n[R"U5R5URlX!lUR S5IShv�N nXC:HoU(d�[R"SU4SXC45S[R"5;d[R"U5(a[R"U5OSS [R"5;d[R"U5(a[R"U5OS S .-nS S U0-n[[R"U55eSngN�7f) z#Test getting cached domain history.� example.com� 2000-01-01�@��domain� creation_date�age_daysNr%r�r�r�r�r�ro)r�r�r�rrr�get_domain_historyr5r6r7r8r9r:r;r<r�s r�!test_get_domain_history_cache_hit�2TestCacheManager.test_get_domain_history_cache_hit�s����$�)�� � � '+�j�j��&=�&D�&D�&F� ���#�(��$�7�7� �F�F���$�$�$�$�$�v�$�$�$�$�$�$�v�$�$�$�$�v�$�$�$�$�$�$��$�$�$�$��$�$�$�$�$�$�$�G�s�AE�E�C-Ec���# �X!lSSSS.nURSU5IShv�N URR5 URRSnUSnSoeU:How(do[ R "SU4S XV45[ R"U5[ R"U5S .-nS S U0-n [[ R"U 55eS=n=pvUS nSoeU:How(do[ R "SU4S XV45[ R"U5[ R"U5S .-nS S U0-n [[ R"U 55eS=n=pvgGNC7f)zTest caching domain history.r�r�r�r�Nrz"url_reputation:history:example.comr%r�r�r�rprr3) r�set_domain_historyrrQr�r5r6r:r;r<) rr"r�historyr�r�rCrjr�rzs r�test_set_domain_history�(TestCacheManager.test_set_domain_history�s���)��$�)�� �� �.�.�}�g�F�F�F����+�+�-����)�)�!�,���A�w�>�>�>�>�>�>�>�>�>�w�>�>�>�w�>�>�>�>�>�>�>�>�>�>�>��A�w� �&� �&� � � � � �w� � � �w� � � �&� � � � � � � � G�s�"E*�E'�EE*c��# �SS/S//URlX!lUR5IShv�N nUSnSoTULof(do[R "SU4SXE45[R "U5[R "U5S .-nS S U0-n[[R"U55eS=n=peUS nS oTU:Hof(do[R "SU4SXE45[R "U5[R "U5S .-nS S U0-n[[R"U55eS=n=peUSnSoTU:Hof(do[R "SU4SXE45[R "U5[R "U5S .-nS S U0-n[[R"U55eS=n=peUSnSoTU:Hof(do[R "SU4SXE45[R "U5[R "U5S .-nS S U0-n[[R"U55eS=n=pegGN7f)zTest getting cache statistics.�url_reputation:validation:1�url_reputation:validation:2�url_reputation:history:1N�enabledTr.�z%(py1)s is %(py4)sr�r�rp�validation_entriesr�r%r��history_entriesr� total_entries�) rrWr� get_statsr5r6r:r;r<) rr"r�statsr�rCrjr�rzs r�test_get_stats_with_redis�*TestCacheManager.test_get_stats_with_redis�s����,�-K� L� (� )�' � ���#�)��#�-�-�/�/���Y��'�4�'�4�'�'�'�'�'��'�'�'��'�'�'�4�'�'�'�'�'�'�'��)�*�/�a�/�a�/�/�/�/�/�*�/�/�/�*�/�/�/�a�/�/�/�/�/�/�/��&�'�,�1�,�1�,�,�,�,�,�'�,�,�,�'�,�,�,�1�,�,�,�,�,�,�,��_�%�*��*��*�*�*�*�*�%�*�*�*�%�*�*�*��*�*�*�*�*�*�*� 0�s�0I�I �HIc��V# �SUlUR5IShv�N nUSnSoCULoU(do[R"SU4SX445[R"U5[R"U5S.-nSSU0-n[ [R "U55eS=n=pTgN�7f) z/Test getting stats when Redis is not available.Nr�Fr.r�r�r�rp)rr�r5r6r:r;r<)rr"r�r�rCrjr�rzs r�test_get_stats_no_redis�(TestCacheManager.test_get_stats_no_redis�su���#� ��#�-�-�/�/���Y��(�5�(�5�(�(�(�(�(��(�(�(��(�(�(�5�(�(�(�(�(�(�(�0�s�B)�B'�B B)c��t# �[SUS9 [5n/URlUR 5IShv�N nUR nSoTULof(d�[ R"SU4SXE45S[R"5;d[ R"U5(a[ R"U5OS[ R"U5[ R"U5S.-nSS U0-n[[ R"U55eS=n=peUS n S oiULo�(do[ R"S U 4S X�45[ R"U 5[ R"U5S.-n SSU 0-n [[ R"U 55eS=n =p�SSS5 gGNh!,(df  g=f7f)z'Test that get_stats ensures connection.rLrNrMrOr!r(r,r-r�Tr.r�r�r�rp)rr rrr�rr5r6r7r8r9r:r;r<) rrr!r�rArBrCrDrEr�rjr�rzs r�!test_get_stats_ensures_connection�2TestCacheManager.test_get_stats_ensures_connection�s����@�z� Z�"�n�G�+-�J�O�O� (�!�+�+�-�-�E��=�=� ,�� ,��,� ,� ,� ,� ,�=� ,� ,� ,� ,� ,� ,�7� ,� ,� ,� ,�7� ,� ,� ,�=� ,� ,� ,�� ,� ,� ,� ,� ,� ,� ,���#� +�t� +�t�+� +� +� +� +�#� +� +� +�#� +� +� +�t� +� +� +� +� +� +� +�[� Z�.� [� Z�s-� F8�/F'�F$�EF'� F8�$F'�' F5�1F8c���# �/SQURlX!lUR5IShv�N URR S5 UR R 5 gN:7f)zTest clearing the cache.)r�r�r�Nzurl_reputation:*)rrr� clear_cache�assert_called_withrrQ�rr"rs r�test_clear_cache�!TestCacheManager.test_clear_cachesW���( � ���$� )���'�'�)�)�)����*�*�+=�>����,�,�.� *�s�-A,�A*�;A,c��# �/URlX!lUR5IShv�N URR 5 gN7f)z'Test clearing cache when no keys exist.N)rrrr�r�assert_not_calledr�s r�test_clear_cache_no_keys�)TestCacheManager.test_clear_cache_no_keyssB���(*� ���$�(���'�'�)�)�)����+�+�-� *�s�+A�A � Ac���# �[S5URl[S5URl[S5URlX!lUR S5IShv�N nSoCULoU(d�[R"SU4SX445S[R"5;d[R"U5(a[R"U5OS[R"U5S.-nSS U0-n[[R"U55eS=pTURS0S 5IShv�N UR!5IShv�N nUS n S o�U LoD(do[R"SU4S X�45[R"U 5[R"U 5S.-n SSU 0-n [[R"U 55eS=n =pJgGNpN�N�7f)z,Test that exceptions are handled gracefully.z Redis errorrcNr.r�r�rfrhr+Tr�Fr�r�r�rp)rVrrWrrrr�r5r6r7r8r9r:r;r<r�r�) rr"rr�rjrArkrDr�r�rCr�rzs r�test_exception_handling�(TestCacheManager.test_exception_handlings;���&/�}�%=� ���"�'0��'?� ���$�&/� �&>� ���#�(��%�:�:�;P�Q�Q�����~�����v�������v�����v�������������1�1�2G��T�R�R�R�#�-�-�/�/���Y��(�5�(�5�(�(�(�(�(��(�(�(��(�(�(�5�(�(�(�(�(�(�(� R� S�/�s8�A)G"�+G�,C G"�9G�:G"�G �B G"�G"� G"�N)"�__name__� __module__� __qualname__�__firstlineno__�__doc__�pytest�fixturerr"�mark�asynciorFrIrSrXr\r_rlr�r�r�r�r�r�r�r�r�r�r�r�r�r�r��__static_attributes__r�rrr r s���&� �^�^� �� � �^�^�'��'� �[�[���-��-� �[�[���:��:�  �[�[���1��1� �[�[��� )�� )� �[�[���-��-� �[�[���.��.�F� G� �[�[��� ,�� ,� �[�[������ �[�[������ �[�[���#��#�* �[�[��� �� � �[�[���S��S� �[�[��� %�� %� �[�[���!��!�" �[�[��� +�� +� �[�[���)��)� �[�[��� ,�� ,� �[�[��� /�� /� �[�[���.��.� �[�[���)��)rr )r��builtinsr7�_pytest.assertion.rewrite� assertion�rewriter5r�� unittest.mockrrrrrr�� redis.asyncior�url_reputation_checker.cacher r r�rr�<module>r�s-����� �;�;�� ��5�^)�^)r

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/prismon/reputation-checker-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server