
    5i-                         d 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
  G d d      Z G d d      Z G d d	      Z G d
 d      Z G d d      Z G d d      Z G d d      Zy)z
E2E API Integration Tests for ReceptionistAI.

Tests the FastAPI backend endpoints based on:
- /mnt/e/genesis-system/RECEPTIONISTAI/QUICK_START.md
- localhost:8000/docs (FastAPI auto-generated docs)
    N)expectc                   "    e Zd ZdZd Zd Zd Zy)TestAPIHealthz"API health and availability tests.c                    t        j                  | 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  }t        j                  d	      d
z   d|iz  }t        t        j                  |            dx}x}}y)z Verify API server is accessible.
/v1/health   timeout   ==z3%(py2)s
{%(py2)s = %(py0)s.status_code
} == %(py5)sresponsepy0py2py5zAPI health check failed
>assert %(py7)spy7Nrequestsgetstatus_code
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanationselfapi_urlr   @py_assert1@py_assert4@py_assert3@py_format6@py_format8s           +/mnt/e/genesis-system/tests/e2e/test_api.pytest_api_server_runningz%TestAPIHealth.test_api_server_running   s    <<7): 6B##EsE#s*EEE#sEEEEEExEEExEEE#EEEsEEE,EEEEEEEE    c                    t        j                  | dd      }|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  }t        j                  d	      d
z   d|iz  }t        t        j                  |            dx}}|d   }ddg}||v }|st        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }	t        j                  d|d          dz   d|	iz  }
t        t        j                  |
            dx}x}}y)z*Verify health endpoint returns valid JSON.r   r   r	   statusinz%(py1)s in %(py3)sdatapy1py3z&Health response missing 'status' field
>assert %(py5)sr   Nhealthyok)z%(py1)s in %(py4)s)r5   py4Unexpected status: z
>assert %(py6)spy6)r   r   jsonr   r   r   r   r   r   r    r!   r"   )r$   r%   r   r3   @py_assert0@py_assert2@py_format4r)   r(   @py_format5@py_format7s              r+   test_health_endpoint_responsez+TestAPIHealth.test_health_endpoint_response   s    <<7): 6B}}Ix4IIIx4IIIxIIIIII4III4IIII!IIIIIIIH~Z)T!2Z~!22ZZZ~!2ZZZ~ZZZ!2ZZZ6I$x.IY4ZZZZZZZZr-   c                    t        j                  | 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  }t        j                  d	      d
z   d|iz  }t        t        j                  |            dx}x}}y)z#Verify OpenAPI docs are accessible.z/docsr   r	   r   r   r   r   r   zAPI docs not accessibler   r   Nr   r#   s           r+   test_api_docs_availablez%TestAPIHealth.test_api_docs_available   s    <<7)5 11=##EsE#s*EEE#sEEEEEExEEExEEE#EEEsEEE,EEEEEEEEr-   N)__name__
__module____qualname____doc__r,   rC   rE    r-   r+   r   r      s    ,F
[Fr-   r   c                   (    e Zd ZdZd Zd Zd Zd Zy)TestConversationEndpointsz!Test conversation/chat endpoints.c                 l   dddd}ddd}t        j                  | d||d	
      }|j                  }ddg}||v }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d|j                         dz   d|iz  }	t        t        j                  |	            dx}x}}|j                         }
g }d}||
v }|}|sd}||
v }|}|snt        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  }t        j                  d      d z   d!|iz  }t        t        j                  |            dx}x}x}x}x}}y)"z)Test POST /v1/conversation/text endpoint.bus_20260215092501_4ecb2567What are your hours?test_session_001business_idmessage
session_idapplication/jsonHgw_live_GIZxDFqNWku4yCPuUpt9mhO8dVTr49tcPrLQdBVWWUXmVt0l4Iiwufpprb3Ju2uLzContent-Typez	X-API-Key/v1/conversation/text
   r=   headersr
   r      r0   z3%(py2)s
{%(py2)s = %(py0)s.status_code
} in %(py5)sr   r   r;   r   r   NrS   )z%(py3)s in %(py5)sr3   )r6   r   z%(py7)s)z%(py10)s in %(py12)s)py10py12z%(py14)spy14   z Response missing expected fieldsz
>assert %(py17)spy17)r   postr   r   r   r   r   r   r   r    r!   r"   r=   append_format_boolop)r$   r%   payloadr[   r   r&   r'   r(   r)   r*   r3   r?   r>   @py_assert9@py_assert11@py_format13@py_format15@py_format16@py_format18s                      r+   test_text_conversation_endpointz9TestConversationEndpoints.test_text_conversation_endpoint&   s    9-,
 /c

 ==i,-	
 ##_Sz_#z1___#z______x___x___#___z___5HI]I]H^3________ }}ZzZzT!ZYZY$%6ZZZZzTZZZzZZZZZZTZZZTZZZZZZZY$ZZZYZZZZZZ$ZZZ$ZZZZZZZZZZ8ZZZZZZZZr-   c                    dddd}ddd}t        j                  | d||d	
      }|j                  }ddg}||v }|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)z3Test conversation with phone number (lead capture).rN   z&My name is John, call me on 0412345678test_session_002rQ   rU   rV   rW   rX   rY   rZ   r   r\   r0   r]   r   r   assert %(py7)sr   Nr   rc   r   r   r   r   r   r   r   r!   r"   
r$   r%   rf   r[   r   r&   r'   r(   r)   r*   s
             r+    test_conversation_with_lead_dataz:TestConversationEndpoints.test_conversation_with_lead_data@   s     9?,
 /c

 ==i,-	
 ##1Sz1#z1111#z111111x111x111#111z1111111r-   c                 *   dddd}ddd}t        j                  | d||d	
      }|j                  }g d}||v }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d|j                         dz   d|iz  }	t        t        j                  |	            dx}x}}y)z0Test API handles invalid business ID gracefully.invalid_business_idTest messagetest_session_003rQ   rU   rV   rW   rX   rY   rZ   )  i    r0   r]   r   r   zExpected error, got r   r   Nr   rc   r   r   r   r   r   r   r   r    r!   r"   rr   s
             r+   test_invalid_business_idz2TestConversationEndpoints.test_invalid_business_idV   s     1%,
 /c

 ==i,-	
 ##ee#6eee#eeeeeexeeexeee#eeeeee:NxOcOcNd8eeeeeeeer-   c                    dddd}t        j                  | d|d      }|j                  }g d}||v }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d|j                         dz   d|iz  }t        t        j                  |            dx}x}}y)z!Test API requires authentication.rN   rv   test_session_004rQ   rX   rY   )r=   r
   )i  i  ry   r0   r]   r   r   zExpected auth error, got r   r   Nrz   )	r$   r%   rf   r   r&   r'   r(   r)   r*   s	            r+   test_missing_api_keyz.TestConversationEndpoints.test_missing_api_keym   s     9%,
 ==i,-
 ##jj#6jjj#jjjjjjxjjjxjjj#jjjjjj:ST\ThThSi8jjjjjjjjr-   N)rF   rG   rH   rI   rm   rs   r{   r~   rJ   r-   r+   rL   rL   #   s    +[42,f.kr-   rL   c                       e Zd ZdZd Zd Zy)TestCORSHeadersz/Test CORS configuration for widget integration.c                    dddd}t        j                  | d|d      }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
                  |      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}x}}|j                  }	|	j                  }
d} |
|      }|st        j                  d      dz   dt        j                         v st        j                  |      rt        j
                  |      ndt        j
                  |	      t        j
                  |
      t        j
                  |      t        j
                  |      dz  }t        t        j                  |            dx}	x}
x}}y)z&Verify CORS headers are set correctly.http://localhost:8888POSTzcontent-type,x-api-key)OriginzAccess-Control-Request-MethodzAccess-Control-Request-HeadersrX   r   r[   r
   Access-Control-Allow-Originr0   )z/%(py1)s in %(py5)s
{%(py5)s = %(py3)s.headers
}r   )r5   r6   r   z CORS Allow-Origin header missingr   r   NzAccess-Control-Allow-Methodsz!CORS Allow-Methods header missingzd
>assert %(py8)s
{%(py8)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.headers
}.get
}(%(py6)s)
})r   r   r:   r<   py8)r   optionsr[   r   r   r   r   r   r   r    r!   r"   r   )r$   r%   r[   r   r>   r'   r?   r)   r*   r&   r(   @py_assert5@py_assert7@py_format9s                 r+   test_cors_headers_presentz)TestCORSHeaders.test_cors_headers_present   sQ    .-3.F
 ##i,-
 -d0@0@d,0@@ddd,0@ddd,dddddddddddd0@dddBddddddddh##h$Bh#$BChChhEhhhhhhhxhhhxhhhhhh#hhh$BhhhChhhhhhr-   c                    ddi}t        j                  | d|d      }|j                  j                  d      }ddg}||v }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }t        j                  d|       dz   d|iz  }t        t        j                  |            dx}}y)z Verify widget origin is allowed.r   r   r   r   r   r   *r0   )z%(py0)s in %(py3)sallowed_originr   r6   zOrigin not allowed: r7   r   N)r   r   r[   r   r   r   r   r   r   r    r!   r"   )	r$   r%   r[   r   r   r?   r&   r@   r)   s	            r+   test_cors_allows_widget_originz.TestCORSHeaders.test_cors_allows_widget_origin   s     -
 <<iz"
 "))--.KL"%'>!?h~!??hhh~!?hhhhhh~hhh~hhh!?hhhCWXfWgAhhhhhhhr-   N)rF   rG   rH   rI   r   r   rJ   r-   r+   r   r      s    9i&ir-   r   c                   "    e Zd ZdZd Zd Zd Zy)TestErrorHandlingz'Test API error handling and validation.c                    ddd}t        j                  | 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  }t        j                  d|j                         dz   d|iz  }t        t        j                  |            dx}x}}y)z Test API handles malformed JSON.rU   rV   rW   rX   zinvalid json {{{r   )r3   r[   r
   ry   r   r   r   r   zExpected 422, got r   r   Nrz   )	r$   r%   r[   r   r&   r'   r(   r)   r*   s	            r+   test_malformed_jsonz%TestErrorHandling.test_malformed_json   s     /c
 ==i,-#	
 ##WsW#s*WWW#sWWWWWWxWWWxWWW#WWWsWWW.@AUAU@V,WWWWWWWWr-   c                 
   ddi}ddd}t        j                  | 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  }t        j                  d      dz   d|iz  }	t        t        j                  |	            dx}x}}y)z#Test API validates required fields.rT   test_session_005rU   rV   rW   rX   r   rZ   ry   r   r   r   r   zShould validate required fieldsr   r   Nrz   rr   s
             r+   test_missing_required_fieldsz.TestErrorHandling.test_missing_required_fields   s     ,
 /c

 ==i,-	
 ##MsM#s*MMM#sMMMMMMxMMMxMMM#MMMsMMM,MMMMMMMMr-   c                    dddd}ddd}t        j                  | d||d	
      }|j                  }ddg}||v }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d      dz   d|iz  }	t        t        j                  |	            dx}x}}y)z Test API handles empty messages.rN    test_session_006rQ   rU   rV   rW   rX   r   rZ   rx   ry   r0   r]   r   r   zShould reject empty messager   r   Nrz   rr   s
             r+   test_empty_messagez$TestErrorHandling.test_empty_message   s     9,
 /c

 ==i,-	
 ##PSzP#z1PPP#zPPPPPPxPPPxPPP#PPPzPPP3PPPPPPPPr-   N)rF   rG   rH   rI   r   r   r   rJ   r-   r+   r   r      s    1X"N*Qr-   r   c                       e Zd ZdZd Zd Zy)TestAPIPerformancez(API response time and performance tests.c                    ddl }|j                         }t        j                  | dd      }|j                         |z
  }|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}||k  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }t	        j                  d|dd      dz   d|iz  }	t        t	        j                  |	            dx}}y)z$Health check should respond quickly.r   Nr   r   r	   r   r   r   r   r   rp   r   g      ?<z%(py0)s < %(py3)sresponse_timer   zHealth check took .2fzs (target: <1s)r7   r   )timer   r   r   r   r   r   r   r   r   r!   r"   r    )r$   r%   r   
start_timer   r   r&   r'   r(   r)   r*   r?   r@   s                r+   test_health_check_fastz)TestAPIPerformance.test_health_check_fast   s   YY[
<<7): 6B		j0##*s*#s****#s******x***x***#***s*******"[}s"[[[}s[[[[[[}[[[}[[[s[[[&8s8K?$[[[[[[[r-   c                    ddl }dddd}ddd	}|j                         }t        j                  | d
||d      }|j                         |z
  }|j                  }ddg}	||	v }
|
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}||k  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }t	        j                  d|dd      dz   d|iz  }t        t	        j                  |            dx}}y)z<Conversation endpoint should respond within reasonable time.r   NrN   rO   test_session_perfrQ   rU   rV   rW   rX      rZ   r   r\   r0   r]   r   r   rp   r   g      $@r   r   r   r   zResponse took r   zs (target: <10s)r7   r   )r   r   rc   r   r   r   r   r   r   r   r!   r"   r    )r$   r%   r   rf   r[   r   r   r   r&   r'   r(   r)   r*   r?   r@   s                  r+   test_conversation_response_timez2TestAPIPerformance.test_conversation_response_time   sK    9--
 /c

 YY[
==i,-	
 		j0##1Sz1#z1111#z111111x111x111#111z1111111#Y}t#YYY}tYYYYYY}YYY}YYYtYYY~mC5HHX%YYYYYYYr-   N)rF   rG   rH   rI   r   r   rJ   r-   r+   r   r      s    2	\Zr-   r   c                   T    e Zd ZdZej
                  j                  d      d        Zy)TestRateLimitingz-Test rate limiting behavior (if implemented).z(Rate limiting may not be implemented yet)reasonc                 "   ddd}dddd}g }t        d      D ]9  }t        j                  | d	||d
      }|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  }	t        j                  d      dz   d|	iz  }
t        t        j                  |
            dx}}y)z$Test that rate limiting is enforced.rU   rV   rW   rN   Testtest_rate_limitrQ   d   rX   r   rZ   i  r0   r2   	responsesr4   zRate limiting not enforcedr7   r   N)ranger   rc   rd   r   r   r   r   r   r   r   r    r!   r"   )r$   r%   r[   rf   r   irespr>   r?   r@   r)   s              r+   test_rate_limit_enforcementz,TestRateLimiting.test_rate_limit_enforcement  s    
 /c
 9+
 	s 	/A==)01	D T--.	/ =si===si===s======i===i====!=======r-   N)rF   rG   rH   rI   pytestmarkskipr   rJ   r-   r+   r   r     s+    7[[GH> I>r-   r   c                       e Zd ZdZd Zy)TestSessionManagementz&Test session handling and persistence.c                    d}ddd}dd|d}t        j                  | d||d	
      }|j                  }ddg}||v }|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}t        j                  | d||d	
      }|j                  }ddg}||v }|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)z/Test messages in same session maintain context.test_session_continuityrU   rV   rW   rN   zMy name is AlicerQ   rX   rY   rZ   r   r\   r0   r]   	response1r   rp   r   NzWhat was my name again?	response2rq   )r$   r%   rT   r[   payload1r   r&   r'   r(   r)   r*   payload2r   s                r+   test_same_session_continuityz2TestSessionManagement.test_same_session_continuity6  sr   .
 /c
 9)$
 MMi,-	
	 $$2c
2$
2222$
222222y222y222$222
2222222 90$
 MMi,-	
	 $$2c
2$
2222$
222222y222y222$222
2222222r-   N)rF   rG   rH   rI   r   rJ   r-   r+   r   r   3  s
    0'3r-   r   )rI   builtinsr   _pytest.assertion.rewrite	assertionrewriter   r   r   playwright.sync_apir   r   rL   r   r   r   r   r   rJ   r-   r+   <module>r      sp       &F F,Zk Zkz#i #iL>Q >QB(Z (ZV> >B*3 *3r-   