
    iJ                       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mZmZmZ ddlmZmZmZmZ ddlZdZee
j,                  vre
j,                  j/                  de        ej0                         d        Z ej0                         d        Z ej0                         d	        Zdd
Z G d d      Z G d d      Z G d d      Z G d d      Z y)uS  
Story 9.04 — Module 9 RAG MCP Tools Integration Tests
=======================================================
All external calls (Qdrant, PostgreSQL, Gemini, orchestrator) are FULLY MOCKED.
No real network traffic or credentials required.

Test summary (13 tests):

Class TestSearchPlatformKb (4 tests — black-box):
  BB  test_search_returns_results       — Non-empty query → rag_context result returned
  BB  test_platform_filter_passed       — platform="hubspot" → rag_query called, filtered
  BB  test_empty_query_returns_message  — Empty query → helpful message, no rag call
  BB  test_top_k_passed                 — top_k=10 → passed through to underlying call

Class TestListPlatformKbs (3 tests — black-box):
  BB  test_list_shows_platforms         — Registered platforms appear in output
  BB  test_list_shows_stats             — Vector counts and PG history appear
  BB  test_list_empty_graceful          — No platforms registered → helpful message

Class TestIngestPlatformKb (4 tests — black-box + white-box):
  BB  test_trigger_ingestion            — Valid platform → ingest_platform called
  BB  test_invalid_platform_error       — Unknown platform → error message returned
  BB  test_max_pages_respected          — max_pages=50 → passed to orchestrator
  BB  test_returns_summary              — Output includes pages/chunks/vectors counts

Class TestToolRegistration (2 tests — white-box):
  WB  test_register_adds_3_tools        — register_kb_tools → 3 new tools added
  WB  test_concurrent_search_safe       — Multiple search calls → all succeed
    )annotationsN)AnyDictList)	AsyncMock	MagicMockpatchcallz/mnt/e/genesis-systemc                 .    i  G fdd      }  |        S )z9A minimal FastMCP stand-in that records registered tools.c                  ,    e Zd Z fdZe fd       Zy)mock_mcp.<locals>.FakeMCPc                    fd}|S )Nc                &    | | j                   <   | S N__name__fn
registereds    =/mnt/e/genesis-system/tests/kb/test_m9_rag_mcp_integration.py	decoratorz1mock_mcp.<locals>.FakeMCP.tool.<locals>.decorator:   s    *,
2;;'	     selfr   r   s     r   toolzmock_mcp.<locals>.FakeMCP.tool9   s     r   c                    S r   r   r   r   s    r   _toolsz mock_mcp.<locals>.FakeMCP._tools?   s	    r   Nr   
__module____qualname__r   propertyr   r   s   r   FakeMCPr   8   s    	 
	 
	r   r%   r   )r%   r   s    @r   mock_mcpr&   3   s     "$J	 	 9r   c                L    ddl }ddlm} ddlm} |j                  |        | |fS )zCImport and register kb_tools on the mock MCP, return (mcp, module).r   N)kb_tools)	importlib%mcp_servers.genesis_core_kb_tools_modgenesis_core_kb_tools_modmcp_servers.genesis_corer(   register_kb_tools)r&   r)   _modmods       r   kb_tools_moduler0   F   s%     88(#S=r   c                x    t         j                  j                  dd       ddl}ddl}|j                  |        | S )z.Register kb_tools on a mock MCP and return it.r   ./mnt/e/genesis-system/mcp-servers/genesis-coreN)syspathinsertr)   r(   r-   )r&   r)   r/   s      r   registered_mcpr6   S   s0     HHOOAGH(#Or   c                    | j                   S r   )r   )r&   s    r   
_get_toolsr8   b   s    ??r   c                      e Zd ZdZd Z ed      d        Z ed      d        Z ed      d        Z ed      d        Z	y	)
TestSearchPlatformKbz%BB tests for search_platform_kb tool.c                    i  G fdd      } |       }t         j                  j                  dd       dd l}|j	                  |       |S )Nc                  ,    e Zd Z fdZe fd       Zy)/TestSearchPlatformKb._make_mcp.<locals>.FakeMCPc                    fd}|S )Nc                &    | | j                   <   | S r   r   r   s    r   r   zGTestSearchPlatformKb._make_mcp.<locals>.FakeMCP.tool.<locals>.decoratorr       .0Jr{{+Ir   r   r   s     r   r   z4TestSearchPlatformKb._make_mcp.<locals>.FakeMCP.toolq        ! r   c                    S r   r   r   s    r   r   z6TestSearchPlatformKb._make_mcp.<locals>.FakeMCP._toolsw   	    !!r   Nr    r$   s   r   r%   r=   p       ! " "r   r%   r   r2   r3   r4   r5   r(   r-   r   r%   mcpr/   r   s       @r   	_make_mcpzTestSearchPlatformKb._make_mcpm   D    %'
		" 		" iKLc"
r   core.rag_query.rag_contextc                   d|_         | j                         }|j                  d   } |dd      }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}}y)z>BB: A valid query returns the context string from rag_context.z=== BLOODSTREAM KNOWLEDGE (3 matches) ===
[1] Telnyx AI Assistants (score: 0.92, type: PLATFORM_KB)
    Source: https://developers.telnyx.com/docs/ai
    How to create an AI assistant on Telnyx...
search_platform_kbz&How do I create a Telnyx AI assistant?   querytop_kzBLOODSTREAM KNOWLEDGEinz%(py1)s in %(py3)sresultpy1py3assert %(py5)spy5NTelnyx)return_valuerH   r   
@pytest_ar_call_reprcompare	_saferepr@py_builtinslocals_should_repr_global_nameAssertionError_format_explanation)	r   mock_rag_contextrG   searchrT   @py_assert0@py_assert2@py_format4@py_format6s	            r   test_search_returns_resultsz0TestSearchPlatformKb.test_search_returns_results   s    ? 	% nn01FaP&0&&0000&&000&000000&000&0000000!x6!!!!x6!!!x!!!!!!6!!!6!!!!!!!r   zcore.rag_query.rag_queryc                @   dddddddg|_         | j                         }|j                  d   } |d	dd
      }|j                          |j                  }d	}t        |      }||v }|st        j                  d|fd||f      t        j                  |      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                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}g }d}|j                  } |       }||v }|}|sd}||v }|}|st        j                  d|fd||f      t        j                  |      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      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nd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)!zBBB: platform='hubspot' triggers rag_query with client-side filter.zHubSpot CRM Setupg333333?PLATFORM_KBz!https://knowledge.hubspot.com/crmzHow to set up HubSpot CRM...hubspot)titlescoretypesourcecontentplatformrL   z	CRM setuprM   )rO   rs   rP   rQ   )z0%(py1)s in %(py6)s
{%(py6)s = %(py3)s(%(py4)s)
}strcall_kwargs)rV   rW   py4py6assert %(py8)spy8NBLOODSTREAMzD%(py3)s in %(py9)s
{%(py9)s = %(py7)s
{%(py7)s = %(py5)s.lower
}()
}rT   rW   rY   py7py9%(py11)spy11)z%(py14)s in %(py16)s)py14py16z%(py18)spy18   zassert %(py21)spy21)r[   rH   r   assert_called_once	call_argsrt   r\   r]   r^   r_   r`   ra   rb   rc   lowerappend_format_boolop)r   mock_rag_queryrG   re   rT   ru   rf   @py_assert5rg   @py_format7@py_format9@py_assert1@py_assert6@py_assert8@py_assert4@py_assert13@py_assert15@py_format10@py_format12@py_format17@py_format19@py_format20@py_format22s                          r   test_platform_filter_passedz0TestSearchPlatformKb.test_platform_filter_passed   s   
 -%=9%	'
# nn01kIQG))+$...c+..{.....{....{......c...c......+...+...........EyEFLLELNEyN*EmEmv.EEEEEyNEEEyEEEEEEFEEEFEEELEEENEEEEEEEmvEEEmEEEEEEvEEEvEEEEEEEEEEEEEEEr   c                h   | j                         }|j                  d   } |dd      }|j                          g }d}|j                  } |       }||v }	|	}
|	sd}|j                  } |       }||v }|}
|
st	        j
                  d|	fd||f      t	        j                  |      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      t	        j                  |      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}x}x}}y)zEBB: Empty query string returns a helpful message without calling rag.rL    rM   rN   z	non-emptyproviderQ   r{   rT   r|   r   r   zJ%(py14)s in %(py20)s
{%(py20)s = %(py18)s
{%(py18)s = %(py16)s.lower
}()
}r   r   r   py20%(py22)spy22r   assert %(py25)spy25N)rH   r   assert_not_calledr   r\   r]   r^   r_   r`   ra   r   r   rb   rc   )r   rd   rG   re   rT   r   rg   r   r   r   rf   r   @py_assert17@py_assert19r   r   r   @py_format21@py_format23@py_format24@py_format26s                        r    test_empty_query_returns_messagez5TestSearchPlatformKb.test_empty_query_returns_message   sK    nn01b***,K{KfllKlnK{n,K	KV\\K\^K	^0KKKKK{nKKK{KKKKKKfKKKfKKKlKKKnKKKKKKK	^KKK	KKKKKKVKKKVKKK\KKK^KKKKKKKKKKKKKKKr   c                    d|_         | j                         }|j                  d   } |dd      }|j                  dd       y)z.BB: top_k=10 is passed through to rag_context.z*=== BLOODSTREAM KNOWLEDGE (10 matches) ===rL   zworkflow automation
   rN   )questionrP   N)r[   rH   r   assert_called_once_with)r   rd   rG   re   rT   s        r   test_top_k_passedz&TestSearchPlatformKb.test_top_k_passed   sK     )U%nn0132>00:OWY0Zr   N)
r   r!   r"   __doc__rH   r	   rj   r   r   r   r   r   r   r:   r:   j   sx    /( '(" )" %&F 'F( '(L )L '([ )[r   r:   c                     e Zd ZdZd Z ed       ed       ed       ed       ed      d                                    Z ed       ed       ed       ed       ed      d	                                    Z ed      d
        Zy)TestListPlatformKbsz$BB tests for list_platform_kbs tool.c                    i  G fdd      } |       }t         j                  j                  dd       dd l}|j	                  |       |S )Nc                  ,    e Zd Z fdZe fd       Zy).TestListPlatformKbs._make_mcp.<locals>.FakeMCPc                    fd}|S )Nc                &    | | j                   <   | S r   r   r   s    r   r   zFTestListPlatformKbs._make_mcp.<locals>.FakeMCP.tool.<locals>.decorator   r@   r   r   r   s     r   r   z3TestListPlatformKbs._make_mcp.<locals>.FakeMCP.tool   rA   r   c                    S r   r   r   s    r   r   z5TestListPlatformKbs._make_mcp.<locals>.FakeMCP._tools   rC   r   Nr    r$   s   r   r%   r      rD   r   r%   r   r2   rE   rF   s       @r   rH   zTestListPlatformKbs._make_mcp   rI   r   zcore.kb.pg_store.get_connectionz&core.kb.pg_store.get_ingestion_historyz'core.kb.qdrant_store.get_platform_stats&core.kb.platform_registry.get_platform(core.kb.platform_registry.list_platformsc                j   ddg|_         t               }d|_        ||_         di d|_         g |_         t               }||_         | j                         }|j                  d   }	 |	       }
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}}y)z9BB: Registered platform names appear in the output table.rm   telnyxHubSpoti  total_vectors	platformslist_platform_kbsrQ   rS   rT   rU   rX   rY   N)r[   r   display_namerH   r   r\   r]   r^   r_   r`   ra   rb   rc   )r   mock_list_platformsmock_get_platformmock_get_statsmock_get_historymock_get_connmock_platform	mock_connrG   	list_toolrT   rf   rg   rh   ri   s                  r   test_list_shows_platformsz-TestListPlatformKbs.test_list_shows_platforms   s#    -6x+@(!%.")6&8<2&N#(*%K	%."nnJJ23	"yF""""yF"""y""""""F"""F"""""""!x6!!!!x6!!!x!!!!!!6!!!6!!!!!!!r   c                &   dg|_         t               }d|_        ||_         ddddiid|_         dddd	g|_         t               }||_         | j                         }|j                  d
   }	 |	       }
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}}g }d}||
v }|}|sd}||
v }|}|sXt        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  }|j                  |       |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  }|j                  |       t        j                  |d      i z  }dd|iz  }t        t        j                  |            dx}x}x}x}x}}y)z>BB: Qdrant vector total and PG history dates appear in output.r   rZ   i   countr   z2026-02-26 10:00:00.000000x   iH  )completed_atpages_fetchedchunks_createdr   2048rQ   rS   rT   rU   rX   rY   NzTotal vectorsz%(py3)s in %(py5)srW   rY   %(py7)sr}   z%(py10)s in %(py12)spy10py12%(py14)sr   r   assert %(py17)spy17)r[   r   r   rH   r   r\   r]   r^   r_   r`   ra   rb   rc   r   r   )r   r   r   r   r   r   r   r   rG   r   rT   rf   rg   rh   ri   r   r   @py_assert9@py_assert11@py_format8@py_format13@py_format15@py_format16@py_format18s                           r   test_list_shows_statsz)TestListPlatformKbs.test_list_shows_stats   s    -5:(!%-")6&!"WdO4'
# !=!$"%)
% K	%."nnJJ23	vvv<<&(<F<Ff,<<<<<&<<<<<<<<<&<<<&<<<<<<<Ff<<<F<<<<<<f<<<f<<<<<<<<<<<<<<r   c                P   g |_         | j                         }|j                  d   } |       }g }d}|j                  } |       }||v }	|	}
|	sd}|j                  } |       }||v }|}
|
st	        j
                  d|	fd||f      t	        j                  |      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      t	        j                  |      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}x}x}}y)u;   BB: No platforms registered → returns a friendly message.r   nor   rQ   r{   rT   r|   r   r   r   r   r   r   r   r   r   N)r[   rH   r   r   r\   r]   r^   r_   r`   ra   r   r   rb   rc   )r   r   rG   r   rT   r   rg   r   r   r   rf   r   r   r   r   r   r   r   r   r   r   s                        r   test_list_empty_gracefulz,TestListPlatformKbs.test_list_empty_graceful  sC    ,.(nnJJ23	GtGv||G|~Gt~%GGGG)GGGGGt~GGGtGGGGGGvGGGvGGG|GGG~GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGr   N)	r   r!   r"   r   rH   r	   r   r   r   r   r   r   r   r      s    .( ,-
34
45
34
56" 7 5 6 5 .
"0 ,-
34
45
34
56= 7 5 6 5 .
=B 56H 7Hr   r   c                      e Zd ZdZd ZddZ ede       ed      d               Z ed       ed      d	               Z	 ede       ed      d
               Z
 ede       ed      d               Zy)TestIngestPlatformKbz*BB + WB tests for ingest_platform_kb tool.c                    i  G fdd      } |       }t         j                  j                  dd       dd l}|j	                  |       |S )Nc                  ,    e Zd Z fdZe fd       Zy)/TestIngestPlatformKb._make_mcp.<locals>.FakeMCPc                    fd}|S )Nc                &    | | j                   <   | S r   r   r   s    r   r   zGTestIngestPlatformKb._make_mcp.<locals>.FakeMCP.tool.<locals>.decorator,  r@   r   r   r   s     r   r   z4TestIngestPlatformKb._make_mcp.<locals>.FakeMCP.tool+  rA   r   c                    S r   r   r   s    r   r   z6TestIngestPlatformKb._make_mcp.<locals>.FakeMCP._tools1  rC   r   Nr    r$   s   r   r%   r   *  rD   r   r%   r   r2   rE   rF   s       @r   rH   zTestIngestPlatformKb._make_mcp'  rI   r   c                B    dd dddddg ddd
}|j                  |       |S )	Nr   2   rM   i^  r   g      )@	completed)
rs   customer_idr   pages_skippedr   vectors_upsertederrorserror_detailsduration_secondsstatus)update)r   	overridesbases      r   _make_statsz TestIngestPlatformKb._make_stats;  s:     ! # $!
 	Ir   z$core.kb.orchestrator.ingest_platform)new_callabler   c                    t               }d|_        ||_        | j                         |_        | j	                         }|j
                  d   } |dd      }|j                  dd       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}}y)u@   BB: Valid platform → ingest_platform called with correct args.rZ   ingest_platform_kbr   d   rs   	max_pagesrQ   rS   rT   rU   rX   rY   N)r   r   r[   r   rH   r   r   r\   r]   r^   r_   r`   ra   rb   rc   r   r   mock_ingestmock_configrG   ingestrT   rf   rg   rh   ri   s              r   test_trigger_ingestionz+TestIngestPlatformKb.test_trigger_ingestionK  s      k#+ )4&#'#3#3#5 nn01S9++X+M!x6!!!!x6!!!x!!!!!!6!!!6!!!!!!!r   r   c                b   d|_         ddg|_         | j                         }|j                  d   } |dd      }g }d}||v }|}	|sd}
|
|v }|}	|	sXt        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  }|j                  |       |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  }|j                  |       t        j                  |d      i z  }dd|iz  }t        t        j                  |            dx}	x}x}x}x}
}g }d}||v }|}	|sd}
|
|v }|}	|	sXt        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  }|j                  |       |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  }|j                  |       t        j                  |d      i z  }dd|iz  }t        t        j                  |            dx}	x}x}x}x}
}y)uB   BB: Unknown platform → helpful error message returned, no crash.Nrm   r   r  nonexistent_platformr  r  UnknownrQ   r   rT   r   r   r}   r   r   r   r   r   r   r   )r[   rH   r   r\   r]   r^   r_   r`   ra   r   r   rb   rc   )r   r   r   rG   r
  rT   r   rg   r   rf   r   r   ri   r   r   r   r   r   s                     r   test_invalid_platform_errorz0TestIngestPlatformKb.test_invalid_platform_error[  s    *.&,5x+@(nn01!73GF%F%/F9F93FFFFF%FFF%FFFFFFFFFFFFFFFF9FFF9FFFFFFFFFFFFFFFFFFFFFFF8y8yF"8h8h&&88888yF888y888888F888F8888888h&888h888888&888&88888888888888r   c                    t               }d|_        ||_        | j                  d      |_        | j	                         }|j
                  d   } |dd       |j                  dd       y)z6BB: max_pages=50 is passed through to ingest_platform.r   rm   )rs   r  r   r  N)r   r   r[   r   rH   r   r   )r   r   r  r	  rG   r
  s         r   test_max_pages_respectedz-TestIngestPlatformKb.test_max_pages_respectedi  sj      k#, )4&#'#3#3Y#3#G nn01	R0++Y"+Mr   c                   t               }d|_        ||_        | j                  ddd      |_        | j	                         }|j
                  d   } |dd      }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}}y)z>BB: Summary output includes pages, chunks, and vectors counts.rZ   P   i0  )r   r   r   r  r   r  r  80rQ   rS   rT   rU   rX   rY   N560z12.5)r   r   r[   r   rH   r   r\   r]   r^   r_   r`   ra   rb   rc   r  s              r   test_returns_summaryz)TestIngestPlatformKb.test_returns_summaryx  so     k#+ )4&#'#3#3  $4 $
  nn01S9tv~tvtvvuuuvvvr   N)returndict)r   r!   r"   r   rH   r   r	   r   r  r  r  r  r   r   r   r   r   $  s    4(  1	J
34" 5 K" 56
34
9 5 7
9 1	J
34N 5 KN 1	J
34  5 K r   r   c                  8    e Zd ZdZd Zd Z ed      d        Zy)TestToolRegistrationz(WB tests for register_kb_tools() itself.c                .    i  G fdd      } |       S )Nc                  ,    e Zd Z fdZe fd       Zy)5TestToolRegistration._make_fresh_mcp.<locals>.FakeMCPc                    fd}|S )Nc                &    | | j                   <   | S r   r   r   s    r   r   zMTestToolRegistration._make_fresh_mcp.<locals>.FakeMCP.tool.<locals>.decorator  r@   r   r   r   s     r   r   z:TestToolRegistration._make_fresh_mcp.<locals>.FakeMCP.tool  rA   r   c                    S r   r   r   s    r   r   z<TestToolRegistration._make_fresh_mcp.<locals>.FakeMCP._tools  rC   r   Nr    r$   s   r   r%   r    rD   r   r%   r   )r   r%   r   s     @r   _make_fresh_mcpz$TestToolRegistration._make_fresh_mcp  s    %'
		" 		" yr   c                   t         j                  j                  dd       ddl}| j	                         }|j                  |       |j                  }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}}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}	}y)zEWB: register_kb_tools adds exactly 3 named tools to the MCP instance.r   r2   NrL   rQ   rS   toolsrU   rX   rY   r   r     ==)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slen)py0rV   rW   rw   rx   ry   )r3   r4   r5   r(   r!  r-   r   r\   r]   r^   r_   r`   ra   rb   rc   r'  )r   r/   rG   r#  rf   rg   rh   ri   r   r   r   r   s               r   test_register_adds_3_toolsz/TestToolRegistration.test_register_adds_3_tools  s   KL""$c"

#,#u,,,,#u,,,#,,,,,,u,,,u,,,,,,,"+"e++++"e+++"++++++e+++e+++++++#,#u,,,,#u,,,#,,,,,,u,,,u,,,,,,,5zQzQzQss55zQr   rJ   c                   g d|_         t        j                  j                  dd       ddl}| j                         }|j                  |       |j                  d   }t        d      D cg c]  } |d| 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}}|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c c}w )zCWB: Multiple search_platform_kb calls succeed without interference.)z=== RESULT A ===z=== RESULT B ===z=== RESULT C ===r   r2   NrL   r$  zquery rN   c              3  >   K   | ]  }|j                  d         yw)z===N)
startswith).0rs     r   	<genexpr>zCTestToolRegistration.test_concurrent_search_safe.<locals>.<genexpr>  s     811<<&8s   z,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}all)r(  py2rv   r%  )z2%(py2)s
{%(py2)s = %(py0)s.call_count
} == %(py5)srd   )r(  r1  rY   zassert %(py7)sr}   )side_effectr3   r4   r5   r(   r!  r-   r   ranger0  r_   r`   r\   ra   r^   rb   rc   
call_countr]   )r   rd   r/   rG   re   iresultsr   @py_assert3@py_format5r   ri   r   s                r   test_concurrent_search_safez0TestToolRegistration.test_concurrent_search_safe  sM   (
$
 	KL""$c"01@EaI16&A6II888s888888888s888s88888888888888**/a/*a////*a////////////*///a/////// Js   +G9N)r   r!   r"   r   r!  r)  r	   r9  r   r   r   r  r    s)    2  '(0 )0r   r  )r  zdict[str, Any])!r   
__future__r   builtinsr_   _pytest.assertion.rewrite	assertionrewriter\   asyncior3   typingr   r   r   unittest.mockr   r   r	   r
   pytest_PROJECT_ROOTr4   r5   fixturer&   r0   r6   r8   r:   r   r   r  r   r   r   <module>rE     s   < #    
 " " ; ;  ( HHOOA}%  $    K[ K[daH aHPg  g \20 20r   