o
    ©k•j\,  ã                   @   sÒ   d Z ddlZddlm  mZ ddlZddlm	Z	 ddl
mZ ddlmZ ddlmZmZ ddlmZ ejjdd	„ ƒZejjd
d„ ƒZejjdd„ ƒZejjdd„ ƒZejjdd„ ƒZejjdd„ ƒZdd„ ZdS )uŽ  
Tests for agentId tracking on agent messages.

Verifies:
1. Agent messages are saved with the correct agentId.
2. User (visitor) messages have no agentId (null/absent).
3. When Agent A handles part of a conversation, it times out, and Agent B
   claims the re-ring â€” messages from each agent show their own correct,
   DIFFERENT agentId.
4. History retrieval endpoints return the agentId field.
é    N)Úget_database)Úcreate_session)Úget_or_create_conversation)Úcreate_messageÚget_messages_by_conversation_id)Úadd_active_sessionc                 Ã   sj  �t ƒ }t|dd�I dH }|d }t||dƒI dH }|d }t|||dddd	�I dH }|d
 }d}||k}	|	sZt d|	fd||f¡t |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}|d }d}||k}	|	s�t d|	fd||f¡t |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}t	||ƒI dH }dd„ |D ƒ}t
|ƒ}	d}|	|k}|sõt d|fd|	|f¡dt ¡ v sÅt t
¡rÊt t
¡nddt ¡ v sÖt |¡rÛt |¡ndt |	¡t |¡dœ }dd|i }tt |¡ƒ‚d }	 }}|d d
 }d}||k}	|	�s-t d|	fd||f¡t |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}dS )zIAn agent message saved with agent_id should have agentId in the document.Úsite_demo_123©Úsite_idNÚ	sessionIdÚconversationIdÚagentzHello from agent_alphaÚagent_alpha)Úconversation_idÚ
session_idÚroleÚcontentÚagent_idÚagentId©ú==©z%(py1)s == %(py4)s©Úpy1Úpy4úassert %(py6)sÚpy6r   c                 S   ó   g | ]
}|d  dkr|‘qS ©r   r   © ©Ú.0Úmr   r   ú=/web/html/dev/chatbot/backend/tests/test_agent_id_tracking.pyÚ
<listcomp>+   ó    z6test_agent_message_stores_agent_id.<locals>.<listcomp>é   ©z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sÚlenÚ
agent_msgs©Úpy0r   Úpy3r   úassert %(py8)sÚpy8r   )r   r   r   r   Ú
@pytest_arÚ_call_reprcompareÚ	_safereprÚAssertionErrorÚ_format_explanationr   r(   Ú@py_builtinsÚlocalsÚ_should_repr_global_name)ÚclientÚdbÚsessÚsidÚconvÚcidÚmsg_docÚ@py_assert0Ú@py_assert3Ú@py_assert2Ú@py_format5Ú@py_format7Úmessagesr)   Ú@py_assert5Ú@py_assert4Ú@py_format9r   r   r#   Ú"test_agent_message_stores_agent_id   s(   €új	j®trG   c                 Ã   sr  �t ƒ }t|dd�I dH }|d }t||dƒI dH }|d }t|||ddd�I dH }d	}||v}|sbt d
|fd||f¡t |¡dt ¡ v sKt 	|¡rPt |¡nddœ }	dd|	i }
t
t |
¡ƒ‚d }}|d }d}||k}|s•t d|fd||f¡t |¡t |¡dœ }dd|i }t
t |¡ƒ‚d } }}t||ƒI dH }dd„ |D ƒ}t|ƒ}d}||k}|sût d|fd||f¡dt ¡ v sËt 	t¡rÐt t¡nddt ¡ v sÜt 	|¡rát |¡ndt |¡t |¡dœ }dd|i }t
t |¡ƒ‚d } }}d	}|d }||v}|�s1t d
|fd ||f¡t |¡t |¡dœ }dd|i }t
t |¡ƒ‚d } }}dS )!z6A user (visitor) message should have no agentId field.r   r	   Nr   r   ÚuserúHello from visitor)r   r   r   r   r   ©únot in)z%(py1)s not in %(py3)sr=   )r   r,   úassert %(py5)sÚpy5r   r   r   r   r   r   c                 S   r   ©r   rH   r   r    r   r   r#   r$   F   r%   z5test_user_message_has_no_agent_id.<locals>.<listcomp>r&   r'   r(   Ú	user_msgsr*   r-   r.   r   ©z%(py1)s not in %(py4)s)r   r   r   r   r/   r0   r1   r4   r5   r6   r2   r3   r   r(   )r7   r8   r9   r:   r;   r<   r=   r>   r@   Ú@py_format4Ú@py_format6r?   rA   rB   rC   rO   rD   rE   rF   r   r   r#   Ú!test_user_message_has_no_agent_id0   s&   €ûxj®prS   c                 Ã   s:  �t ƒ }t|dd�I dH }|d }t||dƒI dH }|d }t|||dddd	�I dH  t|||dd
dd	�I dH  t|||ddƒI dH  t|||dddd	�I dH  t|||dddd	�I dH  t||ƒI dH }t|ƒ}d}||k}	|	s¶t d|	fd||f¡dt 	¡ v s†t 
t¡r‹t t¡nddt 	¡ v s—t 
|¡rœt |¡ndt |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}|d d }d}||k}|sít d|fd||f¡t |¡t |¡dœ }dd|i }
tt |
¡ƒ‚d } }}|d d }d}||k}|�s%t d|fd||f¡t |¡t |¡dœ }dd|i }
tt |
¡ƒ‚d } }}d}|d }||v}|�s[t d |fd!||f¡t |¡t |¡dœ }dd|i }
tt |
¡ƒ‚d } }}|d" d }d}||k}|�s“t d|fd||f¡t |¡t |¡dœ }dd|i }
tt |
¡ƒ‚d } }}|d# d }d}||k}|�sËt d|fd||f¡t |¡t |¡dœ }dd|i }
tt |
¡ƒ‚d } }}td$d%„ |D ƒƒ}ddh}||k}|�st d|fd&||f¡d't 	¡ v �süt 
|¡�rt |¡nd't |¡d(œ }d)d*|i }tt |¡ƒ‚d }}dS )+zÌ
    Scenario: Agent A handles part of a conversation, it times out / disconnects,
    and Agent B claims the re-ring. Messages from each agent should record their
    own correct, DIFFERENT agentId.
    r   r	   Nr   r   r   zAgent A message 1r   )r   zAgent A message 2rH   zVisitor replyzAgent B message 1Ú
agent_betazAgent B message 2é   r   r'   r(   rC   r*   r-   r.   r   r   r   r   r   r   r&   é   rJ   rP   é   é   c                 s   s$   � | ]}|  d ¡r|  d ¡V  qdS )r   N)Úgetr    r   r   r#   Ú	<genexpr>s   s   €" zHtest_rering_different_agents_have_different_agent_ids.<locals>.<genexpr>)z%(py0)s == %(py3)sÚ	agent_ids©r+   r,   rL   rM   )r   r   r   r   r   r(   r/   r0   r4   r5   r6   r1   r2   r3   Úset)r7   r8   r9   r:   r;   r<   rC   r@   rD   rE   rB   rF   r>   r?   rA   r[   Ú@py_assert1rQ   rR   r   r   r#   Ú5test_rering_different_agents_have_different_agent_idsK   s(   €®nplpp†r_   c                 Ã   sÄ  �t ƒ }t|dd�I dH }|d }ddlm} |ƒ }t|d|ddd	� | jd
|dddœd�}|j}d}||k}	|	smt d|	fd||f¡dt	 
¡ v sNt |¡rSt |¡ndt |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}|  d|› d�¡}|j}d}||k}	|	s»t d|	fd||f¡dt	 
¡ v sœt |¡r¡t |¡ndt |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}| ¡ }dd„ |d D ƒ}t|ƒ}d}||k}|�s"t d|fd||f¡dt	 
¡ v sðt t¡rõt t¡nddt	 
¡ v �st |¡�rt |¡ndt |¡t |¡d œ }d!d"|i }tt |¡ƒ‚d } }}|d d# }d}	||	k}|�sZt d|fd$||	f¡t |¡t |	¡d%œ }d&d'|i }tt |¡ƒ‚d } }}	dS )(z‘
    The POST /api/v1/handoff/message endpoint should store the agent's ID
    on the message document and return it in the session history.
    r   r	   Nr   r   ©Ú	AsyncMockÚIN_CHATr   ©Ú
status_valÚassigned_agent_idú/api/v1/handoff/messagezHello from agent alpha©r   Úmessager   ©ÚjsonéÈ   r   ©z3%(py2)s
{%(py2)s = %(py0)s.status_code
} == %(py5)sÚresp©r+   Úpy2rM   úassert %(py7)sÚpy7ú/api/v1/session/ú/history?siteId=site_demo_123Úhistory_respc                 S   r   r   r   r    r   r   r#   r$   “   r%   zAtest_handoff_message_endpoint_stores_agent_id.<locals>.<listcomp>rC   r&   ©ú>=©z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} >= %(py6)sr(   r)   r*   r-   r.   r   r   r   r   r   ©r   r   Úunittest.mockra   r   ÚpostÚstatus_coder/   r0   r4   r5   r6   r1   r2   r3   rY   rj   r(   )r7   r8   r9   r:   ra   Úmock_wsrm   r^   rE   r?   rR   Ú@py_format8rt   Úhistoryr)   r@   rD   rB   rF   r>   rA   r   r   r#   Ú-test_handoff_message_endpoint_stores_agent_idw   s&   €
ýŠŠ´tr   c                 Ã   sô  �t ƒ }t|dd�I dH }|d }ddlm} |ƒ }t|d|ddd	� | jd
|ddœd�}|j}d}||k}	|	slt d|	fd||f¡dt	 
¡ v sMt |¡rRt |¡ndt |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}|  d|› d�¡}|j}d}||k}	|	sºt d|	fd||f¡dt	 
¡ v s›t |¡r t |¡ndt |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}| ¡ }dd„ |d D ƒ}t|ƒ}d}||k}|�s!t d|fd||f¡dt	 
¡ v sït t¡rôt t¡nddt	 
¡ v �st |¡�rt |¡ndt |¡t |¡d œ }d!d"|i }tt |¡ƒ‚d } }}|d }|j}d#}||ƒ}d}||u }|�slt d$|fd%||f¡t |¡t |¡t |¡t |¡t |¡d&œ }d'd(|i }tt |¡ƒ‚d } } } } }}dS ))zY
    User/visitor messages should have agentId=null in the session history response.
    r   r	   Nr   r   r`   rb   r   rc   z/api/v1/messagerI   )r   rh   ri   rk   r   rl   rm   rn   rp   rq   rr   rs   rt   c                 S   r   rN   r   r    r   r   r#   r$   ²   r%   zEtest_visitor_message_has_null_agent_id_in_history.<locals>.<listcomp>rC   r&   ru   rw   r(   rO   r*   r-   r.   r   )Úis)zJ%(py7)s
{%(py7)s = %(py3)s
{%(py3)s = %(py1)s.get
}(%(py5)s)
} is %(py10)s)r   r,   rM   rq   Úpy10zassert %(py12)sÚpy12rx   )r7   r8   r9   r:   ra   r|   rm   r^   rE   r?   rR   r}   rt   r~   rO   r@   rD   rB   rF   r>   Ú@py_assert6Ú@py_assert9Ú@py_assert8Ú@py_format11Ú@py_format13r   r   r#   Ú1test_visitor_message_has_null_agent_id_in_history˜   s$   €
þŠŠ´¦rˆ   c              	   Ã   sà  �t ƒ }t|dd�I dH }|d }ddlm} |ƒ }t|d|dd� | jd	|d
dœd�}|j}d}||k}	|	skt d|	fd||f¡dt	 
¡ v sLt |¡rQt |¡ndt |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}| ¡ d }d
}	||	k}|s¢t d|fd||	f¡t |¡t |	¡dœ }dd|i }tt |¡ƒ‚d } }}	| jd|dd
dœd�}|j}d}||k}	|	sòt d|	fd||f¡dt	 
¡ v sÓt |¡rØt |¡ndt |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}|d  |ddid œ¡I dH }d}||u}|�sBt d!|fd"||f¡d#t	 
¡ v �s't |¡�r,t |¡nd#t |¡d$œ }d%d&|i }
tt |
¡ƒ‚d }}|d' }t||ƒI dH }d(d)„ |D ƒ}t|ƒ}d*}||k}|�s¯t d|fd+||f¡d,t	 
¡ v �s}t t¡�r‚t t¡nd,d-t	 
¡ v �s�t |¡�r•t |¡nd-t |¡t |¡d.œ }d/d0|i }tt |¡ƒ‚d } }}|d d1 }d
}	||	k}|�sçt d|fd||	f¡t |¡t |	¡dœ }dd|i }tt |¡ƒ‚d } }}	| jd2|d3d4œd�}|j}d}||k}	|	�s9t d|	fd||f¡d5t	 
¡ v �st |¡�rt |¡nd5t |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}|d6  d|id7dddd8d9œi¡I dH  t|d|dd� | jd	|d:dœd�}|j}d}||k}	|	�s§t d|	fd||f¡d;t	 
¡ v �sˆt |¡�r�t |¡nd;t |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}| ¡ d }d:}	||	k}|�sßt d|fd||	f¡t |¡t |	¡dœ }dd|i }tt |¡ƒ‚d } }}	| jd|d<d:dœd�}|j}d}||k}	|	�s2t d|	fd||f¡d=t	 
¡ v �st |¡�rt |¡nd=t |¡t |¡dœ }
dd|
i }tt |¡ƒ‚d } }	}|d  |d|id>œ¡I dH }d}||u}|�s‡t d!|fd"||f¡d?t	 
¡ v �sgt |¡�rlt |¡nd?t |¡d$œ }t d@¡dA d&|i }
tt |
¡ƒ‚d }}|d' }t||ƒI dH }dBd)„ |D ƒ}t|ƒ}d*}||k}|�sôt d|fd+||f¡d,t	 
¡ v �sÂt t¡�rÇt t¡nd,dCt	 
¡ v �sÕt |¡�rÚt |¡ndCt |¡t |¡d.œ }d/d0|i }tt |¡ƒ‚d } }}|d d1 }d:}	||	k}|�s,t d|fd||	f¡t |¡t |	¡dœ }dd|i }tt |¡ƒ‚d } }}	|d d1 }|d d1 }	||	k}|�sht dD|fdE||	f¡t |¡t |	¡dœ }dd|i }tt |¡ƒ‚d } }}	dS )Fa"  
    End-to-end re-ring scenario via HTTP endpoints:
    1. Agent A claims session and sends a message.
    2. Session goes to ENDED (simulated).
    3. Session re-rings, Agent B claims and sends a message.
    4. Verify Agent A's message has agentId=agent_alpha (in conv 1).
    5. Verify Agent B's message has agentId=agent_beta (in conv 2).
    
    Note: After end+re-ring, get_or_create_conversation creates a new
    conversation. So the two agents' messages end up in separate conversations.
    This test verifies both independently.
    r   r	   Nr   r   r`   ÚRINGING)rd   z/api/v1/handoff/acceptr   )r   r   ri   rk   r   rl   Úaccept_resp_arn   rp   rq   ÚassignedAgentIdr   r   r   r   rf   zAgent Alpha hererg   Ú
msg_resp_aÚconversationsz$neÚended)r   Ústatus©úis not©z%(py0)s is not %(py3)sÚconv_ar\   rL   rM   r   c                 S   r   r   r   r    r   r   r#   r$   â   r%   z6test_rering_scenario_via_endpoints.<locals>.<listcomp>r&   r'   r(   Úagent_msgs_ar*   r-   r.   r   z/api/v1/handoff/endr   )r   ÚendedByÚend_respÚsessionsz$setÚrule)r�   r‹   Ú
assignedAtÚmoderT   Úaccept_resp_bzAgent Beta hereÚ
msg_resp_b)r   r   Úconv_bz,Expected a second conversation after re-ringz
>assert %(py5)sc                 S   r   r   r   r    r   r   r#   r$     r%   Úagent_msgs_b)ú!=)z%(py1)s != %(py4)s)r   r   ry   ra   r   rz   r{   r/   r0   r4   r5   r6   r1   r2   r3   rj   Úfind_oner   r(   Ú
update_oneÚ_format_assertmsg)r7   r8   r9   r:   ra   r|   rŠ   r^   rE   r?   rR   r}   r>   r@   rA   rB   rŒ   r“   rQ   Ú	conv_a_idÚmsgs_ar”   rD   rF   r–   r›   rœ   r�   Ú	conv_b_idÚmsgs_brž   r   r   r#   Ú"test_rering_scenario_via_endpoints·   st   €
þŠn
ýŠ~¸p
þ�
þ
þ�p
ý�
ÿˆ¸p|r§   c                 C   sÌ  ddl }tƒ }| t|dd�¡}|d }ddlm} |ƒ }t|d|ddd	� |  d
¡�}| d|ddœ¡ W d  ƒ n1 s?w   Y  | |d  	d|i¡¡}d}	||	u}
|
sˆt
 d|
fd||	f¡dt ¡ v smt
 |¡rrt
 |¡ndt
 |	¡dœ }dd|i }tt
 |¡ƒ‚d }
}	| t||d ƒ¡}dd„ |D ƒ}t|ƒ}	d}|	|k}|sît
 d|fd|	|f¡dt ¡ v s¾t
 t¡rÃt
 t¡nddt ¡ v sÏt
 |¡rÔt
 |¡ndt
 |	¡t
 |¡dœ }dd|i }tt
 |¡ƒ‚d }	 }}|d d  }d}||k}	|	�s&t
 d|	fd!||f¡t
 |¡t
 |¡d"œ }d#d$|i }tt
 |¡ƒ‚d } }	}|d d% }d}||k}	|	�s^t
 d|	fd!||f¡t
 |¡t
 |¡d"œ }d#d$|i }tt
 |¡ƒ‚d } }	}dS )&z”
    When an agent sends a message over /ws/agent WebSocket,
    the persisted MongoDB message document must store the sending agent's agentId.
    r   Nr   r	   r   r`   rb   Úagent_gammarc   z/ws/agent?agentId=agent_gammaÚagent_messagezLive reply via agent websocket)Útyper   rh   r�   r�   r’   r;   r\   rL   rM   r   c                 S   r   r   r   r    r   r   r#   r$   .  r%   z:test_agent_message_via_agent_websocket.<locals>.<listcomp>r&   r   r'   r(   r)   r*   r-   r.   r   r   r   r   r   r   )Úasyncior   Úrunr   ry   ra   r   Úwebsocket_connectÚ	send_jsonr    r/   r0   r4   r5   r6   r1   r2   r3   r   r(   )r7   r«   r8   r9   r:   ra   r|   Úwsr;   r@   r^   rQ   rR   Úmsgsr)   rD   rE   rB   rF   r>   r?   rA   r   r   r#   Ú&test_agent_message_via_agent_websocket  s*   
ýÿx®ptr±   )Ú__doc__Úbuiltinsr4   Ú_pytest.assertion.rewriteÚ	assertionÚrewriter/   ÚpytestÚapp.databaser   Ú#app.repositories.session_repositoryr   Ú(app.repositories.conversation_repositoryr   Ú#app.repositories.message_repositoryr   r   Úapp.services.presencer   ÚmarkÚanyiorG   rS   r_   r   rˆ   r§   r±   r   r   r   r#   Ú<module>   s(    "


+
 

\