U
    �AcjRF  ã                   @   sd  d Z ddlmZ ddlmZ zddlZW n ek
r@   dZY nX eZddlm	Z	 ddl
mZ ddlmZmZ ddlmZ dd	lmZmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZmZmZm Z m!Z! ddl"m#Z# ddl$m%Z% ddl&m'Z'm(Z( G dd„ de j)ƒZ*G dd„ dej+ƒZ+G dd„ de,ƒZ-G dd„ deƒZ.G dd„ dƒZ/G dd„ deƒZ0dS )z#
Tests for L{twisted.web.distrib}.
é    )Úabspath)ÚparseStringN)ÚskipIf)ÚverifyObject)ÚdeferÚreactor)ÚglobalLogPublisher)ÚfailureÚfilepath)Úpb©Ú
SIZE_LIMIT)Úproto_helpers)ÚTestCase)ÚclientÚdistribÚresourceÚserverÚstatic)ÚHeaders)Ú_render)ÚDummyChannelÚDummyRequestc                   @   s   e Zd ZdS )ÚMySiteN)Ú__name__Ú
__module__Ú__qualname__© r   r   úA/tmp/pip-unpacked-wheel-nrvc_22y/twisted/web/test/test_distrib.pyr   #   s   r   c                   @   s   e Zd ZdZdZdd„ ZdS )ÚPBServerFactoryzÅ
    A PB server factory which keeps track of the most recent protocol it
    created.

    @ivar proto: L{None} or the L{Broker} instance most recently returned
        from C{buildProtocol}.
    Nc                 C   s   t j | |¡| _| jS ©N)r   r   ÚbuildProtocolÚproto)ÚselfÚaddrr   r   r   r!   2   s    zPBServerFactory.buildProtocol)r   r   r   Ú__doc__r"   r!   r   r   r   r   r   '   s   r   c                   @   s   e Zd ZdZdS )ÚArbitraryErrorz%
    An exception for this test.
    N)r   r   r   r%   r   r   r   r   r&   7   s   r&   c                   @   s„   e Zd ZdZdZdZdZdd„ Zdd„ Zdd„ Z	dd	„ Z
d
d„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ ZdS )ÚDistribTestsNc                    sØ   t  ¡ t  ¡ g‰ | jdk	r>| jjdk	r>| jj ‡ fdd„¡ nˆ d  d¡ | jdk	rŒ| jjdk	rŒ| jjj ‡ fdd„¡ | jjjj	 
¡  nˆ d  d¡ | jdk	r´ˆ  | j ¡ ¡ | jdk	rÎˆ  | j ¡ ¡ t  ˆ ¡S )z‹
        Clean up all the event sources left behind by either directly by
        test methods or indirectly via some distrib API.
        Nc                      s   ˆ d   d ¡S ©Nr   ©Úcallbackr   ©Údlr   r   Ú<lambda>J   ó    z'DistribTests.tearDown.<locals>.<lambda>r   c                      s   ˆ d   d ¡S )Né   r)   r   r+   r   r   r-   N   r.   r/   )r   ÚDeferredÚf1r"   ÚnotifyOnDisconnectr*   ÚsubZ	publisherZbrokerÚ	transportZloseConnectionÚport1ÚappendÚstopListeningÚport2ZgatherResults©r#   r   r+   r   ÚtearDownC   s    

zDistribTests.tearDownc                 C   sÚ   t  ¡ }| dt dd¡¡ t |¡}tt 	|¡ƒ| _
t d| j
¡| _t d| j ¡ j¡| _t  ¡ }| d| j¡ t|ƒ}t d|¡| _t t¡}d| j ¡ j› d�}| d	¡}| d
|¡}| tj¡ | | jd¡ |S )Ns   theres   rootz
text/plainr   ú	127.0.0.1s   herezhttp://127.0.0.1:z/here/thereÚasciió   GET)r   ÚResourceÚputChildr   ÚDatar   ÚSiter   r   ÚResourcePublisherr1   r   Ú	listenTCPr5   ÚResourceSubscriptionÚgetHostÚportr3   r   r8   r   ÚAgentÚencodeÚrequestÚaddCallbackÚreadBodyÚassertEqual)r#   Zr1Zsite1Zr2Úf2ÚagentÚurlÚdr   r   r   ÚtestDistribX   s"    


zDistribTests.testDistribc                 C   s¢   t  ¡ }| d|¡ t |¡}tt |¡ƒ | _}t	j
d|dd�}|  |j¡ | ¡ }t |j|j¡ | _}t |¡}t	j
d|dd�}	|  |	j¡ |	 ¡ }
|	|
fS )zû
        Set up a resource on a distrib site using L{ResourcePublisher}.

        @param child: The resource to publish using distrib.

        @return: A tuple consisting of the host and port on which to contact
            the created site.
        s   childr   r;   )Z	interface)r   r>   r?   r   rA   r   r   rB   r1   r   rC   Z
addCleanupr7   rE   rD   ÚhostrF   r3   )r#   ÚchildZdistribRootZdistribSiteZdistribFactoryZdistribPortr$   ZmainRootZmainSiteÚmainPortÚmainAddrr   r   r   Ú_setupDistribServerl   s    	
ÿ

z DistribTests._setupDistribServerc                 K   sX   |   |¡\}}t t¡}d|j› d|j› d�}| d¡}|jd|f|Ž}| tj	¡ |S )a¡  
        Set up a resource on a distrib site using L{ResourcePublisher} and
        then retrieve it from a L{ResourceSubscription} via an HTTP client.

        @param child: The resource to publish using distrib.
        @param **kwargs: Extra keyword arguments to pass to L{Agent.request} when
            requesting the resource.

        @return: A L{Deferred} which fires with the result of the request.
        úhttp://ú:ú/childr<   r=   )
rV   r   rG   r   rR   rF   rH   rI   rJ   rK   )r#   rS   ÚkwargsrT   rU   rN   rO   rP   r   r   r   Ú_requestTest‡   s    

zDistribTests._requestTestc                 K   sZ   |   |¡\}}d|j› d|j› d�}| d¡}t t¡jd|f|Ž}dd„ }| |¡ |S )a;  
        Set up a resource on a distrib site using L{ResourcePublisher} and
        then retrieve it from a L{ResourceSubscription} via an HTTP client.

        @param child: The resource to publish using distrib.
        @param **kwargs: Extra keyword arguments to pass to L{Agent.request} when
            requesting the resource.

        @return: A L{Deferred} which fires with a tuple consisting of a
            L{twisted.test.proto_helpers.AccumulatingProtocol} containing the
            body of the response and an L{IResponse} with the response itself.
        rW   rX   rY   r<   r=   c                    s8   t  ¡ ‰ ˆ ˆ ¡ t ¡  }ˆ _| ‡ ‡fdd„¡ |S )Nc                    s   ˆ ˆfS r    r   )Ú_©ÚprotocolÚresponser   r   r-   ±   r.   zGDistribTests._requestAgentTest.<locals>.cbCollectBody.<locals>.<lambda>)r   ZAccumulatingProtocolZdeliverBodyr   r0   ZclosedDeferredrJ   )r_   rP   r   r]   r   ÚcbCollectBody­   s
    
z5DistribTests._requestAgentTest.<locals>.cbCollectBody)	rV   rR   rF   rH   r   rG   r   rI   rJ   )r#   rS   rZ   rT   rU   rO   rP   r`   r   r   r   Ú_requestAgentTestš   s    

zDistribTests._requestAgentTestc                    s|   i ‰t  ¡ ‰t ˆ¡ dg‰G ‡‡fdd„dtjƒ}‡‡‡fdd„‰ ˆj|ƒ tddgiƒd�}‡ ‡‡fd	d
„}| |¡ |S )z†
        The request headers are available on the request object passed to a
        distributed resource's C{render} method.
        Nc                       s   e Zd Z‡ ‡fdd„ZdS )z>DistribTests.test_requestHeaders.<locals>.ReportRequestHeadersc                    s    |ˆ d< ˆ  t|j ¡ ƒ¡ dS )Nr   r.   )ÚupdateÚdictÚrequestHeadersZgetAllRawHeaders©r#   rI   ©Úreqrd   r   r   ÚrenderÂ   s    zEDistribTests.test_requestHeaders.<locals>.ReportRequestHeaders.renderN©r   r   r   rh   r   rf   r   r   ÚReportRequestHeadersÁ   s   rj   c                     sD   dd„ ˆ D ƒ} ˆ  d| ¡ ˆ  d| ¡ ˆ  ˆd | ¡ t ˆ ¡ d S )Nc                 S   s   g | ]}|d  ‘qS )Ú
log_formatr   )Ú.0Úer   r   r   Ú
<listcomp>È   s     zHDistribTests.test_requestHeaders.<locals>.check_logs.<locals>.<listcomp>zconnected to publisherz3could not connect to distributed web service: {msg}r   )ÚassertInr   ZremoveObserver)Zmsgs)ÚlogObserverrg   r#   r   r   Ú
check_logsÇ   s
    z4DistribTests.test_requestHeaders.<locals>.check_logsZfooÚbar)Úheadersc                    s$   ˆj j ˆ ¡ ˆ ˆd dg¡ d S )Ns   Foos   bar)r1   r"   r2   rL   ©Úresult)rq   rd   r#   r   r   ÚcbRequestedÒ   s    z5DistribTests.test_requestHeaders.<locals>.cbRequested)	r   ÚEventLoggingObserverr   ZaddObserverr   r>   r[   r   rJ   )r#   rj   rI   rv   r   )rq   rp   rg   rd   r#   r   Útest_requestHeaders·   s    
 ÿ
z DistribTests.test_requestHeadersc                    s8   G dd„ dt jƒ}ˆ  |ƒ ¡}‡ fdd„}| |¡ |S )z�
        The response code can be set by the request object passed to a
        distributed resource's C{render} method.
        c                   @   s   e Zd Zdd„ ZdS )z>DistribTests.test_requestResponseCode.<locals>.SetResponseCodec                 S   s   |  d¡ dS )NéÈ   Ú ©ZsetResponseCodere   r   r   r   rh   à   s    
zEDistribTests.test_requestResponseCode.<locals>.SetResponseCode.renderNri   r   r   r   r   ÚSetResponseCodeß   s   r|   c                    s:   ˆ   | d jd¡ ˆ   | d jd¡ ˆ   | d jd¡ d S )Nr   r.   r/   ry   s   OK©rL   ÚdataÚcodeÚphrasert   r9   r   r   rv   æ   s    z:DistribTests.test_requestResponseCode.<locals>.cbRequested©r   r>   ra   rJ   ©r#   r|   rI   rv   r   r9   r   Útest_requestResponseCodeÙ   s
    
z%DistribTests.test_requestResponseCodec                    s8   G dd„ dt jƒ}ˆ  |ƒ ¡}‡ fdd„}| |¡ |S )z�
        The response code and message can be set by the request object passed to
        a distributed resource's C{render} method.
        c                   @   s   e Zd Zdd„ ZdS )zEDistribTests.test_requestResponseCodeMessage.<locals>.SetResponseCodec                 S   s   |  dd¡ dS )Nry   ó   some-messagerz   r{   re   r   r   r   rh   õ   s    zLDistribTests.test_requestResponseCodeMessage.<locals>.SetResponseCode.renderNri   r   r   r   r   r|   ô   s   r|   c                    s:   ˆ   | d jd¡ ˆ   | d jd¡ ˆ   | d jd¡ d S )Nr   r.   r/   ry   r„   r}   rt   r9   r   r   rv   û   s    zADistribTests.test_requestResponseCodeMessage.<locals>.cbRequestedr�   r‚   r   r9   r   Útest_requestResponseCodeMessageî   s
    
z,DistribTests.test_requestResponseCodeMessagec                 C   s8   G dd„ dt jƒ}|  |ƒ ¡}| | jdt d ¡ |S )zÞ
        If a string longer than the Banana size limit is passed to the
        L{distrib.Request} passed to the remote resource, it is broken into
        smaller strings to be transported over the PB connection.
        c                   @   s   e Zd Zdd„ ZdS )z0DistribTests.test_largeWrite.<locals>.LargeWritec                 S   s    |  dt d ¡ | ¡  tjS ©Nó   xó   y)Úwriter   Úfinishr   ZNOT_DONE_YETre   r   r   r   rh     s    z7DistribTests.test_largeWrite.<locals>.LargeWrite.renderNri   r   r   r   r   Ú
LargeWrite
  s   r‹   r‡   rˆ   ©r   r>   r[   rJ   rL   r   )r#   r‹   rI   r   r   r   Útest_largeWrite  s    zDistribTests.test_largeWritec                 C   s8   G dd„ dt jƒ}|  |ƒ ¡}| | jdt d ¡ |S )z 
        Like L{test_largeWrite}, but for the case where C{render} returns a
        long string rather than explicitly passing it to L{Request.write}.
        c                   @   s   e Zd Zdd„ ZdS )z2DistribTests.test_largeReturn.<locals>.LargeReturnc                 S   s   dt  d S r†   r   re   r   r   r   rh     s    z9DistribTests.test_largeReturn.<locals>.LargeReturn.renderNri   r   r   r   r   ÚLargeReturn  s   rŽ   r‡   rˆ   rŒ   )r#   rŽ   rI   r   r   r   Útest_largeReturn  s    zDistribTests.test_largeReturnc                    sl   t t ¡ ƒ ˆ_}t d|¡ ˆ_}t d| 	¡ j
¡ ˆ_}tdgƒ‰ t|ˆ ƒ}‡ ‡fdd„}| |¡ |S )zz
        If there is an error issuing the request to the remote publisher, an
        error response is returned.
        r   r;   r.   c              
      s\   ˆ  ˆ jd¡ ˆ tj¡}ˆ  t|ƒd¡ ddddddd	d
ddg
}ˆ  d |¡gˆ j¡ d S )Niô  r/   r.   s   <html>s:     <head><title>500 - Server Connection Lost</title></head>s     <body>s#       <h1>Server Connection Lost</h1>s¦       <p>Connection to distributed server lost:<pre>[Failure instance: Traceback from remote host -- twisted.spread.flavors.NoSuchMethod: No such method: remote_requests   ]</pre></p>s	     </body>s   </html>ó   
)rL   ÚresponseCodeÚflushLoggedErrorsr   ZNoSuchMethodÚlenÚjoinÚwritten)ÚignoredÚerrorsÚexpected©rI   r#   r   r   Ú
cbRendered2  s    òz4DistribTests.test_connectionLost.<locals>.cbRendered)r   r   ZRootr1   r   rC   r5   r   rD   rE   rF   r3   r   r   rJ   )r#   ZserverFactoryZ
serverPortZsubscriptionrP   rš   r   r™   r   Útest_connectionLost"  s     ÿ



z DistribTests.test_connectionLostc                 C   s`   t j | t¡}t tƒ ¡}tdgƒ}t 	|¡}| 
|¡ |  dt|ƒ¡ |  d|d d ¡ dS )zQ
        When a request fails, the string form of the failure is logged.
        r.   r/   zFailure instancer   rk   N)r   rw   ÚcreateWithCleanupr   r	   ÚFailurer&   r   r   ZIssueÚfailedÚassertEqualsr“   ro   )r#   rp   ÚfrI   Úissuer   r   r   Útest_logFailedN  s     ÿ


zDistribTests.test_logFailedc                 C   sf   t j | t¡}tƒ }t |¡}t t	ƒ ¡}| 
|¡ |  t¡ |  dt|ƒ¡ |  |d d |¡ dS )zf
        When L{twisted.web.distrib.Request}'s fail is called, the failure
        is logged.
        r/   r   Zlog_failureN)r   rw   rœ   r   r&   r	   r�   r   ÚRequestr   Zfailr’   rŸ   r“   ZassertIs)r#   rp   Úerrr    rg   r   r   r   Útest_requestFail]  s     ÿ


zDistribTests.test_requestFail)r   r   r   r5   r8   r3   r1   r:   rQ   rV   r[   ra   rx   rƒ   r…   r�   r�   r›   r¢   r¥   r   r   r   r   r'   =   s"   ",r'   c                   @   s$   e Zd Zdd„ Zdd„ Zdd„ ZdS )Ú_PasswordDatabasec                 C   s
   || _ d S r    )Ú_users)r#   Zusersr   r   r   Ú__init__o  s    z_PasswordDatabase.__init__c                 C   s
   t | jƒS r    )Úiterr§   r9   r   r   r   Úgetpwallr  s    z_PasswordDatabase.getpwallc                 C   s*   | j D ]}|d |kr|  S qtƒ ‚d S r(   )r§   ÚKeyError)r#   ÚusernameÚuserr   r   r   Úgetpwnamu  s    

z_PasswordDatabase.getpwnamN)r   r   r   r¨   rª   r®   r   r   r   r   r¦   n  s   r¦   c                   @   st   e Zd ZdZdd„ Zdd„ Zeddœdd	„Zd
d„ Zdd„ Z	dd„ Z
dd„ Zdd„ Zdd„ Zee dƒdd„ ƒZdS )ÚUserDirectoryTestszj
    Tests for L{UserDirectory}, a resource for listing all user resources
    available on a system.
    c                 C   sT   ddddd|   ¡ df| _dddd	d
|   ¡ df| _t| j| jgƒ| _t | j¡| _d S )NÚaliceÚxé{   iÈ  zAlice,,,z/bin/shÚbobéê   i7  zBob,,,)Úmktempr°   r³   r¦   Zdatabaser   ÚUserDirectoryÚ	directoryr9   r   r   r   ÚsetUp‚  s    zUserDirectoryTests.setUpc                 C   s   |   ttj| jƒ¡ dS )zK
        L{UserDirectory} instances provide L{resource.IResource}.
        N)Ú
assertTruer   r   Z	IResourcer·   r9   r   r   r   Útest_interfaceˆ  s    z!UserDirectoryTests.test_interfaceN)ÚnameÚreturnc                 Ã   s>   t |gƒ}| j ||¡}t||ƒ}|I dH  |  |jd¡ dS )zr
        Verify that requesting the C{name} child of C{self.directory} results
        in a 404 response.
        Ni”  )r   r·   ÚgetChildr   rL   r‘   )r#   r»   rI   ru   rP   r   r   r   Ú_404TestŽ  s
    


zUserDirectoryTests._404Testc                 Ã   s   |   d¡I dH  dS )z­
        L{UserDirectory.getChild} returns a resource which renders a 404
        response when passed a string which does not correspond to any known
        user.
        s   carolN©r¾   r9   r   r   r   Útest_getInvalidUser™  s    z&UserDirectoryTests.test_getInvalidUserc                 Ã   s   |   d¡I dH  dS )zÞ
        L{UserDirectory.getChild} returns a resource which renders a 404
        response when passed a string which corresponds to a known user who has
        neither a user directory nor a user distrib socket.
        s   aliceNr¿   r9   r   r   r   Útest_getUserWithoutResource¡  s    z.UserDirectoryTests.test_getUserWithoutResourcec                 C   s\   t  | jd ¡}| d¡}| ¡  tdgƒ}| j d|¡}|  |t	j
¡ |  |j|j¡ dS )z¹
        L{UserDirectory.getChild} returns a L{static.File} instance when passed
        the name of a user with a home directory containing a I{public_html}
        directory.
        éþÿÿÿÚpublic_htmlr³   s   bobN)r
   ÚFilePathr³   rS   Úmakedirsr   r·   r½   ÚassertIsInstancer   ZFilerL   Úpath)r#   ÚhomerÃ   rI   ru   r   r   r   Útest_getPublicHTMLChild©  s    

z*UserDirectoryTests.test_getPublicHTMLChildc                 C   sn   t  | jd ¡}| ¡  | d¡}tdgƒ}| j d|¡}|  |t	j
¡ |  |jd¡ |  t|jƒ|j¡ dS )zà
        L{UserDirectory.getChild} returns a L{ResourceSubscription} instance
        when passed the name of a user suffixed with C{".twistd"} who has a
        home directory containing a I{.twistd-web-pb} socket.
        rÂ   ú.twistd-web-pbr³   s
   bob.twistdÚunixN)r
   rÄ   r³   rÅ   rS   r   r·   r½   rÆ   r   rD   rL   rR   r   rF   rÇ   )r#   rÈ   ÚwebrI   ru   r   r   r   Útest_getDistribChild·  s    

z'UserDirectoryTests.test_getDistribChildc                 C   s(   t dgƒ}d|_|  tj| jj|¡ dS )zr
        L{UserDirectory.render} raises L{UnsupportedMethod} in response to a
        non-I{GET} request.
        rz   ÚPOSTN)r   ÚmethodÚassertRaisesr   ZUnsupportedMethodr·   rh   re   r   r   r   Útest_invalidMethodÆ  s    
z%UserDirectoryTests.test_invalidMethodc                    sx   t  ˆjd ¡ d¡}| ¡  t  ˆjd ¡}| ¡  | d¡ d¡ tdgƒ‰ tˆj	ˆ ƒ}‡ ‡fdd„}| 
|¡ |S )z}
        L{UserDirectory} renders a list of links to available user content
        in response to a I{GET} request.
        rÂ   rÃ   rÊ   r.   rz   c                    sŽ   t d ˆ j¡ƒ}| d¡\}}ˆ |jjd¡ ˆ |j d¡d¡ ˆ |jjjd¡ ˆ |jjd¡ ˆ |j d¡d¡ ˆ |jjjd¡ d S )	Nr.   ÚliÚaÚhrefzalice/zAlice (file)zbob.twistd/zBob (twistd))	r   r”   r•   ZgetElementsByTagNamerL   Z
firstChildZtagNameÚgetAttributer~   )r–   Údocumentr°   r³   r™   r   r   rš   à  s    z2UserDirectoryTests.test_render.<locals>.cbRendered)r
   rÄ   r°   rS   rÅ   r³   Z
setContentr   r   r·   rJ   )r#   rÃ   rÌ   ru   rš   r   r™   r   Útest_renderÏ  s    

zUserDirectoryTests.test_renderzpwd module requiredc                 C   s   t  ¡ }|  |jt¡ dS )z„
        If L{UserDirectory} is instantiated with no arguments, it uses the
        L{pwd} module as its password database.
        N)r   r¶   ZassertIdenticalÚ_pwdÚpwd)r#   r·   r   r   r   Útest_passwordDatabaseï  s    z(UserDirectoryTests.test_passwordDatabase)r   r   r   r%   r¸   rº   Úbytesr¾   rÀ   rÁ   rÉ   rÍ   rÑ   r×   r   rÙ   rÚ   r   r   r   r   r¯   |  s   	 
r¯   )1r%   Úos.pathr   Zxml.dom.minidomr   rÙ   rØ   ÚImportErrorZunittestr   Zzope.interface.verifyr   Ztwisted.internetr   r   Ztwisted.loggerr   Ztwisted.pythonr	   r
   Ztwisted.spreadr   Ztwisted.spread.bananar   Ztwisted.testr   Ztwisted.trial.unittestr   Ztwisted.webr   r   r   r   r   Ztwisted.web.http_headersr   Ztwisted.web.test._utilr   Ztwisted.web.test.requesthelperr   r   rA   r   r   Ú	Exceptionr&   r'   r¦   r¯   r   r   r   r   Ú<module>   s8   
  3