
    Ti!                       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 ddlmZ ddlmZmZmZ ddlZ ee      j+                         j,                  d   Zedz  Z ee      e
j4                  vr"e
j4                  j7                  d ee             dd	Zd
e
j:                  vr e       e
j:                  d
<   ddlmZm Z  dZ!dZ"ddZ# G d d      Z$ G d d      Z%y)zfTests for FRClient.

All websockets calls are mocked so these tests run without websockets installed.
    )annotationsN)Path)
ModuleType)	AsyncMock	MagicMockpatch   srcc                 >    t        d      }  G d d      }|| _        | S )z>Build a minimal websockets stub sufficient for FRClient tests.
websocketsc                      e Zd ZdZy)+_make_fake_websockets.<locals>._FakeConnectz)Placeholder; replaced per-test via patch.N)__name__
__module____qualname____doc__     Q/home/nelsen/Projects/kognitive/orchestrator/src/services/tests/test_fr_client.py_FakeConnectr      s    7r   r   )r   connect)faker   s     r   _make_fake_websocketsr      s$    l#D8 8  DLKr   r   )FRClientFRConfigsC                                                                   zws://kluster.klass.dev:42067/c                    t               }t               |_        t        |       |_        t               }t        |      |_        t        d      |_        |S )zBuild a mock async context manager that looks like a websockets connection.

    Args:
        recv_payload: The string returned by ``ws.recv()``.

    Returns:
        A MagicMock usable as ``async with websockets.connect(...) as ws:``.
    return_valueF)r   r   sendrecv
__aenter__	__aexit__)recv_payloadwsctxs      r   _make_ws_ctxr&   4   sD     
BkBG\2BG
+CB/CN51CMJr   c                  8    e Zd ZdZ	 	 	 	 ddZddZddZddZy)	TestFRConfigz,FRConfig default values and field behaviour.c                @   |j                  dd       t               }|j                  }|t        k(  }|st	        j
                  d|fd|t        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dz  }d	d
|iz  }t        t	        j                  |            d x}}y )NFR_ENDPOINTF)raising==)z0%(py2)s
{%(py2)s = %(py0)s.endpoint
} == %(py4)sconfig_DEFAULT_ENDPOINT)py0py2py4assert %(py6)spy6)delenvr   endpointr/   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation)selfmonkeypatchr.   @py_assert1@py_assert3@py_format5@py_format7s          r   )test_default_endpoint_uses_env_or_klusterz6TestFRConfig.test_default_endpoint_uses_env_or_klusterM   s     	=%83"33333"3333333v333v333333333"3333"33333333r   c                   |j                  dd       t               }|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 )	Nr*   zws://myhost:42067/r,   z0%(py2)s
{%(py2)s = %(py0)s.endpoint
} == %(py5)sr.   r0   r1   py5assert %(py7)spy7)setenvr   r6   r7   r8   r9   r:   r;   r<   r=   r>   )r?   r@   r.   rA   @py_assert4rB   @py_format6@py_format8s           r   test_endpoint_from_envz#TestFRConfig.test_endpoint_from_envT   s    =*>?6"66"66666"6666666v666v666666"66666666r   c                   t               }|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 )N
   r,   z1%(py2)s
{%(py2)s = %(py0)s.timeout_s
} == %(py5)sr.   rH   rJ   rK   )
r   	timeout_sr7   r8   r9   r:   r;   r<   r=   r>   r?   r.   rA   rM   rB   rN   rO   s          r   test_default_timeoutz!TestFRConfig.test_default_timeoutY   s{    %2%2%%%%2%%%%%%v%%%v%%%%%%2%%%%%%%r   c                >   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}}y )Nzws://custom:1234/   )r6   rT   r,   rG   r.   rH   rJ   rK   rS   )r   r6   r7   r8   r9   r:   r;   r<   r=   r>   rT   rU   s          r   test_custom_valueszTestFRConfig.test_custom_values]   s    #6"E5"55"55555"5555555v555v555555"55555555%2%2%%%%2%%%%%%v%%%v%%%%%%2%%%%%%%r   N)r@   zpytest.MonkeyPatchreturnNonerZ   r[   )r   r   r   r   rE   rP   rV   rY   r   r   r   r(   r(   J   s)    64-4	47
&&r   r(   c                     e Zd Z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ej
                  j                  dd       Zej
                  j                  	 	 dd       Zej
                  j                  dd	       Zy
)TestFRClientIdentifyzFRClient.identify() behaviour.c                  K   t        d      }t        |      }t        j                  dddg dddd	g d
dgd      }t	        |      }ddl}t        j                  |d|      5  |j                  t               d{   }d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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   d   }t&        j(                  }	d} |	|      }||k(  }|st        j                  d|fd||f      t        j                   |      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}	x}}|d   d"   }g 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   }d}||u }|slt        j                  d$|fd%||f      t        j                   |      t        j                   |      dz  }dd|iz  }
t#        t        j$                  |
            dx}x}}y7 # 1 sw Y   xY ww)&u:   Valid JSON response → identify() returns detection list.ws://fake:42067/r6   g  eAalicegq=
ףp?)rR      d      )identity
confidencebboxNg?)i,  2   i     	timestamp
detectionsr   r   r      r,   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenresult)r0   py1py3r4   zassert %(py8)spy8rf   z%(py1)s == %(py4)srq   r2   r3   r4   rg   )zL%(py1)s == %(py9)s
{%(py9)s = %(py5)s
{%(py5)s = %(py3)s.approx
}(%(py7)s)
}pytest)rq   rr   rI   rK   py9zassert %(py11)spy11rh      )is)z%(py1)s is %(py4)s)r   r   jsondumpsr&   r   r   objectidentify
_FAKE_JPEGro   r7   r8   r9   r:   r;   r<   r=   r>   rv   approx)r?   r.   clientpayloadr%   r   rp   @py_assert2@py_assert5rM   rD   @py_format9@py_assert0rB   rC   @py_assert6@py_assert8@py_format10@py_format12s                      r   (test_identify_success_returns_detectionsz=TestFRClientIdentify.test_identify_success_returns_detectionsf   s     #56&!**)!(FXY!%TCVW
 7#\\*icB 	7!??:66F	7 6{a{a{ass66{aay$//$////$///$//////////ay&=&--==-*==&*=====&*====&======&===&===-======*========ay 6$66 $66666 $6666 666$66666666ay$,,$,,,,$,,,$,,,,,,,,,, 7	7 	7s1   A%Q'P; P8P;N3Q8P;;Q Qc                  K   t        d      }t        |      }t        j                  dg i      }t	        |      }|j
                  j                  }ddl}t        j                  |d|      5  |j                  t               d{    ddd       |j                  j                  t               y7 ,# 1 sw Y   +xY ww)z4identify() must send the raw bytes to the WebSocket.r`   ra   rm   r   Nr   r   )r   r   r{   r|   r&   r!   r   r   r   r}   r~   r   r   assert_awaited_once_with)r?   r.   r   r   r%   r$   r   s          r    test_identify_sends_binary_framez5TestFRClientIdentify.test_identify_sends_binary_frame   s      #56&!**lB/07#^^((\\*icB 	.//*---	. 	((4 .	. 	.s0   A,C.B6B4B6(C4B66B?;Cc                l  K   t        d      }t        |      }t        j                  dg d      }t	        |      }ddl}t        j                  |d|      5  |j                  t               d{   }d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}}y7 # 1 sw Y   xY ww)u;   Response with empty detections list → returns empty list.r`   ra   g        rk   r   Nr   r   r,   z%(py0)s == %(py3)srp   r0   rr   assert %(py5)srI   )r   r   r{   r|   r&   r   r   r}   r~   r   r7   r8   r9   r:   r;   r<   r=   r>   )r?   r.   r   r   r%   r   rp   r   rA   @py_format4rN   s              r   'test_identify_empty_detections_responsez<TestFRClientIdentify.test_identify_empty_detections_response   s      #56&!**3bAB7#\\*icB 	7!??:66F	7 v|vvv 7	7 	7s1   AD4D(2D&3D(7B/D4&D((D1-D4c                8  K   t        d      }t        |      }ddl}t        j                  |dt        d            5  |j                  t               d{   }d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}}y7 # 1 sw Y   xY ww)u8   Connection failure → identify() returns [] (no raise).zws://unreachable:42067/ra   r   Nr   refusedside_effectr,   r   rp   r   r   rI   )r   r   r   r   r}   ConnectionRefusedErrorr~   r   r7   r8   r9   r:   r;   r<   r=   r>   )	r?   r.   r   r   rp   r   rA   r   rN   s	            r   ,test_identify_connection_error_returns_emptyzATestFRClientIdentify.test_identify_connection_error_returns_empty   s      #<=&!\\	/Ei/P
 	7 "??:66F	7
 v|vvv 7	7 	7s/   =DDDDB/DDDDc                  K   ddl }t        d      }t        |      }t               }t	               |_        t	        |j                               |_        t               }t	        |      |_        t	        d      |_	        ddl
}t        j                  |d|      5  |j                  t               d{   }d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}	}y7 # 1 sw Y   xY ww)u7   asyncio.TimeoutError on recv → identify() returns [].r   Nr`   ra   r   r   Fr   r,   r   rp   r   r   rI   )asyncior   r   r   r   r   TimeoutErrorr    r!   r"   r   r   r}   r~   r   r7   r8   r9   r:   r;   r<   r=   r>   )r?   r   r.   r   r$   r%   r   rp   r   rA   r   rN   s               r   #test_identify_timeout_returns_emptyz8TestFRClientIdentify.test_identify_timeout_returns_empty   s      	#56&![+(<(<(>?k"3!u5\\*icB 	7!??:66F	7 v|vvv 7	7 	7s1   BE9E-7E+8E-<B/E9+E--E62E9c                <  K   t        d      }t        |      }t        d      }ddl}t	        j
                  |d|      5  |j                  t               d{   }d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}}y7 # 1 sw Y   xY ww)u,   Non-JSON response → identify() returns [].r`   ra   zthis is not json {{{r   Nr   r   r,   r   rp   r   r   rI   )r   r   r&   r   r   r}   r~   r   r7   r8   r9   r:   r;   r<   r=   r>   )
r?   r.   r   r%   r   rp   r   rA   r   rN   s
             r   *test_identify_malformed_json_returns_emptyz?TestFRClientIdentify.test_identify_malformed_json_returns_empty   s      #56&!12\\*icB 	7!??:66F	7 v|vvv 7	7 	7s0   ?DDDDB/DDDDc                :  K   t        d      }t        |      }ddl}t        j                  |d      5 }|j                  d       d{   }d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}}j                          y7 # 1 sw Y   xY ww)z5Empty bytes are rejected before opening a connection.r`   ra   r   Nr   r   r,   r   rp   r   r   rI   )r   r   r   r   r}   r~   r7   r8   r9   r:   r;   r<   r=   r>   assert_not_called)
r?   r.   r   r   mock_connectrp   r   rA   r   rN   s
             r   :test_identify_empty_bytes_returns_empty_without_connectingzOTestFRClientIdentify.test_identify_empty_bytes_returns_empty_without_connecting   s     
 #56&!\\*i0 	0L!??3//F	0 v|vvv&&( 0	0 	0s/   2DD	D
DB?DDDDc                j  K   t        d      }t        |      }t        j                  dg i      }t	        |      }ddl}t        j                  |d|      5 }|j                  t               d{    ddd       j                          |j                  }|j                  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}
}	y7 # 1 sw Y   xY ww)z1connect() is called with the configured endpoint.zws://custom-host:9999/ra   rm   r   Nr   r   r,   rt   ru   r3   r4   )r   r   r{   r|   r&   r   r   r}   r~   r   assert_called_once	call_argsargsr7   r8   r<   r=   r>   )r?   r.   r   r   r%   r   r   r   r   rB   r   rC   rD   s                r   "test_identify_uses_config_endpointz7TestFRClientIdentify.test_identify_uses_config_endpoint   s      #;<&!**lB/07#\\*icB 	.l//*---	. 	'') **	~~a <$<< $<<<<< $<<<< <<<$<<<<<<<<	 .	. 	.s1   AD3D'1D%2D'6B/D3%D''D0,D3Nr\   )r   r   r   r   rv   markr   r   r   r   r   r   r   r   r   r   r   r   r^   r^   c   s    ([[- -6 [[5 5  [[  [[  [[ , [[  [[)	) ) [[= =r   r^   )rZ   r   )r#   strrZ   r   )&r   
__future__r   builtinsr9   _pytest.assertion.rewrite	assertionrewriter7   r{   syspathlibr   typesr   unittest.mockr   r   r   rv   __file__resolveparentsROOTSRCr   pathinsertr   modulesservices.fr_clientr   r   r   r/   r&   r(   r^   r   r   r   <module>r      s   
 #    
   5 5  H~''*
Uls8388HHOOAs3x  s{{" 5 7CKK 1 ,
3 ,& &2U= U=r   