U
    
W[pG  ã                   @   sX  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 ddlmZ ddl	m
Z
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mZmZmZ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% 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j+ƒZ,G dd„ dƒZ-G dd„ dej+ƒZ.dS )z#
Tests for L{twisted.web.distrib}.
é    )Úabspath)ÚparseStringN)ÚverifyObject)ÚfilepathÚfailure)ÚreactorÚdefer)Úunittest)Úpb©Ú
SIZE_LIMIT)ÚdistribÚclientÚresourceÚstaticÚserver)ÚDummyRequestÚDummyChannel)Ú_render)Úproto_helpers)ÚHeaders)ÚglobalLogPublisherc                   @   s   e Zd ZdS )ÚMySiteN)Ú__name__Ú
__module__Ú__qualname__© r   r   ú?/usr/lib/python3/dist-packages/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    ,   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%   2   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   ©Zdlr   r   Ú<lambda>F   ó    z'DistribTests.tearDown.<locals>.<lambda>r   c                      s   ˆ d   d ¡S )Né   r(   r   r*   r   r   r+   K   r,   r-   )r   ÚDeferredÚf1r!   ÚnotifyOnDisconnectr)   ÚsubZ	publisherZbrokerZ	transportZloseConnectionÚport1ÚappendÚstopListeningÚport2ZgatherResults©r"   r   r*   r   ÚtearDown?   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	|¡}| tj¡ | | jd¡ |S )
Ns   theres   rootz
text/plainr   ú	127.0.0.1s   herezhttp://127.0.0.1:{}/here/thereÚasciió   GET)r   ÚResourceÚputChildr   ZDatar   ÚSiter   r   ÚResourcePublisherr/   r   Ú	listenTCPr2   ÚResourceSubscriptionÚgetHostÚportr1   r   r5   r   ÚAgentÚformatÚencodeÚrequestÚaddCallbackÚreadBodyÚassertEqual)r"   Zr1Zsite1Zr2Úf2ÚagentÚurlÚdr   r   r   ÚtestDistribV   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   r8   )Z	interface)r   r;   r<   r   r=   r   r   r>   r/   r   r?   Z
addCleanupr4   rA   r@   ÚhostrB   r1   )r"   ÚchildZdistribRootZdistribSiteZdistribFactoryZdistribPortr#   ZmainRootZmainSiteÚmainPortÚmainAddrr   r   r   Ú_setupDistribServerm   s,    	
ÿ
  ÿ ÿ

z DistribTests._setupDistribServerc                 K   sR   |   |¡\}}t t¡}d|j|jf }| 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.
        zhttp://%s:%s/childr9   r:   )
rS   r   rC   r   rO   rB   rE   rF   rG   rH   )r"   rP   ÚkwargsrQ   rR   rK   rL   rM   r   r   r   Ú_requestTestŠ   s    

zDistribTests._requestTestc                 K   sT   |   |¡\}}d |j|j¡}| 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.
        zhttp://{}:{}/childr9   r:   c                    s8   t  ¡ ‰ ˆ ˆ ¡ t ¡  }ˆ _| ‡ ‡fdd„¡ |S )Nc                    s   ˆ ˆfS r   r   )Ú_©ZprotocolÚresponser   r   r+   µ   r,   zGDistribTests._requestAgentTest.<locals>.cbCollectBody.<locals>.<lambda>)r   ZAccumulatingProtocolZdeliverBodyr   r.   ZclosedDeferredrG   )rX   rM   r   rW   r   ÚcbCollectBody±   s
    
z5DistribTests._requestAgentTest.<locals>.cbCollectBody)
rS   rD   rO   rB   rE   r   rC   r   rF   rG   )r"   rP   rT   rQ   rR   rL   rM   rY   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"   rF   ©Úreqr]   r   r   ÚrenderÇ   s
    ÿzEDistribTests.test_requestHeaders.<locals>.ReportRequestHeaders.renderN©r   r   r   ra   r   r_   r   r   ÚReportRequestHeadersÆ   s   rc   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)ÚlogObserverr`   r"   r   r   Ú
check_logsÍ   s    þz4DistribTests.test_requestHeaders.<locals>.check_logsZfooZbar)Zheadersc                    s$   ˆj j ˆ ¡ ˆ ˆd dg¡ d S )Ns   Foos   bar)r/   r!   r0   rI   ©Úresult)rj   r]   r"   r   r   ÚcbRequestedÙ   s    z5DistribTests.test_requestHeaders.<locals>.cbRequested)	r   ÚEventLoggingObserverr   ZaddObserverr   r;   rU   r   rG   )r"   rc   rF   rm   r   )rj   ri   r`   r]   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setResponseCoder^   r   r   r   ra   ç   s    
zEDistribTests.test_requestResponseCode.<locals>.SetResponseCode.renderNrb   r   r   r   r   ÚSetResponseCodeæ   s   rs   c                    s:   ˆ   | d jd¡ ˆ   | d jd¡ ˆ   | d jd¡ d S )Nr   r,   r-   rp   s   OK©rI   ÚdataÚcodeÚphraserk   r6   r   r   rm   ì   s    z:DistribTests.test_requestResponseCode.<locals>.cbRequested©r   r;   rZ   rG   ©r"   rs   rF   rm   r   r6   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 )Nrp   ó   some-messagerq   rr   r^   r   r   r   ra   ú   s    zLDistribTests.test_requestResponseCodeMessage.<locals>.SetResponseCode.renderNrb   r   r   r   r   rs   ù   s   rs   c                    s:   ˆ   | d jd¡ ˆ   | d jd¡ ˆ   | d jd¡ d S )Nr   r,   r-   rp   r{   rt   rk   r6   r   r   rm   ÿ   s    zADistribTests.test_requestResponseCodeMessage.<locals>.cbRequestedrx   ry   r   r6   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   Zfinishr   ZNOT_DONE_YETr^   r   r   r   ra     s    z7DistribTests.test_largeWrite.<locals>.LargeWrite.renderNrb   r   r   r   r   Ú
LargeWrite  s   r   r~   r   ©r   r;   rU   rG   rI   r   )r"   r   rF   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   r^   r   r   r   ra     s    z9DistribTests.test_largeReturn.<locals>.LargeReturn.renderNrb   r   r   r   r   ÚLargeReturn  s   r„   r~   r   r‚   )r"   r„   rF   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   r8   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>ó   
)rI   ÚresponseCodeÚflushLoggedErrorsr
   ZNoSuchMethodÚlenÚjoinÚwritten)ÚignoredÚerrorsZexpected©rF   r"   r   r   Ú
cbRendered4  s    òz4DistribTests.test_connectionLost.<locals>.cbRendered)r   r
   ZRootr/   r   r?   r2   r   r@   rA   rB   r1   r   r   rG   )r"   ZserverFactoryZ
serverPortZsubscriptionrM   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   rd   N)r   rn   ÚcreateWithCleanupr   r   ÚFailurer%   r   r   ZIssueZfailedÚassertEqualsr‰   rh   )r"   ri   ÚfrF   Zissuer   r   r   Útest_logFailedQ  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   rn   r‘   r   r%   r   r’   r   ZRequestr   Zfailrˆ   r“   r‰   ZassertIs)r"   ri   Úerrr”   r`   r   r   r   Útest_requestFaile  s    þ


zDistribTests.test_requestFail)r   r   r   r2   r5   r1   r/   r7   rN   rS   rU   rZ   ro   rz   r|   rƒ   r…   r   r•   r—   r   r   r   r   r&   9   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__y  s    z_PasswordDatabase.__init__c                 C   s
   t | jƒS r   )Úiterr™   r6   r   r   r   Úgetpwall}  s    z_PasswordDatabase.getpwallc                 C   s*   | j D ]}|d |kr|  S qtƒ ‚d S r'   )r™   ÚKeyError)r"   ZusernameÚuserr   r   r   Úgetpwnam  s    

z_PasswordDatabase.getpwnamN)r   r   r   rš   rœ   rŸ   r   r   r   r   r˜   x  s   r˜   c                   @   sn   e 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edkrjde_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,,,)Zmktempr¡   r¤   r˜   Zdatabaser   ÚUserDirectoryÚ	directoryr6   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)Z
assertTruer   r   Z	IResourcer§   r6   r   r   r   Útest_interface•  s    z!UserDirectoryTests.test_interfacec                    s>   t |gƒ‰ ˆj |ˆ ¡}t|ˆ ƒ}‡ ‡fdd„}| |¡ |S )zr
        Verify that requesting the C{name} child of C{self.directory} results
        in a 404 response.
        c                    s   ˆ  ˆ jd¡ d S )Ni”  )rI   r‡   )rŒ   rŽ   r   r   r   ¤  s    z/UserDirectoryTests._404Test.<locals>.cbRendered)r   r§   ÚgetChildr   rG   )r"   Únamerl   rM   r   r   rŽ   r   Ú_404Testœ  s    


zUserDirectoryTests._404Testc                 C   s
   |   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.
        Zcarol©r¬   r6   r   r   r   Útest_getInvalidUserª  s    z&UserDirectoryTests.test_getInvalidUserc                 C   s
   |   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.
        r¡   r­   r6   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¤   N)r   ÚFilePathr¤   rP   Úmakedirsr   r§   rª   ÚassertIsInstancer   ZFilerI   Úpath)r"   Úhomer±   rF   rl   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¤   z
bob.twistdZunixN)r   r²   r¤   r³   rP   r   r§   rª   r´   r   r@   rI   rO   r   rB   rµ   )r"   r¶   ÚwebrF   rl   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.
        rq   ZPOSTN)r   ÚmethodZassertRaisesr   ZUnsupportedMethodr§   ra   r^   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,   rq   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,   ZliÚaZhrefzalice/zAlice (file)zbob.twistd/zBob (twistd))	r   rŠ   r‹   ZgetElementsByTagNamerI   Z
firstChildZtagNameZgetAttributeru   )rŒ   Zdocumentr¡   r¤   rŽ   r   r   r   ö  s    z2UserDirectoryTests.test_render.<locals>.cbRendered)r   r²   r¡   rP   r³   r¤   Z
setContentr   r   r§   rG   )r"   r±   r¹   rl   r   r   rŽ   r   Útest_renderæ  s    

zUserDirectoryTests.test_renderc                 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assertIdenticalZ_pwdÚpwd)r"   r§   r   r   r   Útest_passwordDatabase  s    z(UserDirectoryTests.test_passwordDatabaseNzpwd module required)r   r   r   r$   r¨   r©   r¬   r®   r¯   r·   rº   r¼   r¾   rÀ   r¿   Úskipr   r   r   r   r    ‰  s   		 r    )/r$   Úos.pathr   Zxml.dom.minidomr   r¿   ÚImportErrorZzope.interface.verifyr   Ztwisted.pythonr   r   Ztwisted.internetr   r   Ztwisted.trialr	   Ztwisted.spreadr
   Ztwisted.spread.bananar   Ztwisted.webr   r   r   r   r   Ztwisted.web.test.test_webr   r   Ztwisted.web.test._utilr   Ztwisted.testr   Ztwisted.web.http_headersr   Ztwisted.loggerr   r=   r   r   Ú	Exceptionr%   ZTestCaser&   r˜   r    r   r   r   r   Ú<module>   s4   
  A