o
    ¯btF  ã                   @   sb  d Z ddlmZ ddlmZ zddlZW n ey   dZY nw 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   ú?/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!   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ur| jjdur| jj ‡ fdd„¡ nˆ d  d¡ | jdurF| jjdurF| jjj ‡ fdd„¡ | jjjj	 
¡  nˆ d  d¡ | jdurZˆ  | j ¡ ¡ | jdurgˆ  | 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                      ó   ˆ d   d ¡S ©Nr   ©Úcallbackr   ©Údlr   r   Ú<lambda>J   ó    z'DistribTests.tearDown.<locals>.<lambda>r   c                      r(   )Né   r*   r   r,   r   r   r.   N   r/   r0   )r   ÚDeferredÚf1r"   ÚnotifyOnDisconnectr+   ÚsubÚ	publisherÚbrokerÚ	transportÚloseConnectionÚport1ÚappendÚstopListeningÚport2Ú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   ÚResourcePublisherr2   r   Ú	listenTCPr9   ÚResourceSubscriptionÚgetHostÚportr4   r   r<   r   ÚAgentÚencodeÚrequestÚaddCallbackÚreadBodyÚassertEqual)r#   Úr1Úsite1Ú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@   )Ú	interface)r   rC   rD   r   rF   r   r   rG   r2   r   rH   Ú
addCleanupr;   rJ   rI   ÚhostrK   r4   )r#   ÚchildÚdistribRootÚdistribSiteÚdistribFactoryÚdistribPortr$   ÚmainRootÚmainSiteÚmainPortÚmainAddrr   r   r   Ú_setupDistribServerl   s   	

ÿ
z DistribTests._setupDistribServerc                 K   s\   |   |¡\}}t t¡}d|j› d|j› d�}| d¡}|jd|fi |¤Ž}| 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://ú:ú/childrA   rB   )
rf   r   rL   r   r\   rK   rM   rN   rO   rP   )r#   r]   Úkwargsrd   re   rV   rW   rX   r   r   r   Ú_requestTest‡   s   

zDistribTests._requestTestc                 K   s^   |   |¡\}}d|j› d|j› d�}| d¡}t t¡jd|fi |¤Ž}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.
        rg   rh   ri   rA   rB   c                    s8   t  ¡ ‰ ˆ ˆ ¡ t ¡  }ˆ _| ‡ ‡fdd„¡ |S )Nc                    s   ˆ ˆfS r    r   )Ú_©ÚprotocolÚresponser   r   r.   ±   s    zGDistribTests._requestAgentTest.<locals>.cbCollectBody.<locals>.<lambda>)r   ÚAccumulatingProtocolÚdeliverBodyr   r1   ÚclosedDeferredrO   )ro   rX   r   rm   r   ÚcbCollectBody­   s
   
z5DistribTests._requestAgentTest.<locals>.cbCollectBody)	rf   r\   rK   rM   r   rL   r   rN   rO   )r#   r]   rj   rd   re   rW   rX   rs   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   ó    )ÚupdateÚdictÚrequestHeadersÚgetAllRawHeaders©r#   rN   ©Úreqrx   r   r   ÚrenderÂ   s   zEDistribTests.test_requestHeaders.<locals>.ReportRequestHeaders.renderN©r   r   r   r}   r   r{   r   r   ÚReportRequestHeadersÁ   s    r   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   ÚremoveObserver)Úmsgs)ÚlogObserverr|   r#   r   r   Ú
check_logsÇ   s
   z4DistribTests.test_requestHeaders.<locals>.check_logsÚfooÚbar)Úheadersc                    s$   ˆj j ˆ ¡ ˆ ˆd dg¡ d S )Ns   Foos   bar)r2   r"   r3   rQ   ©Úresult)rˆ   rx   r#   r   r   ÚcbRequestedÒ   s   z5DistribTests.test_requestHeaders.<locals>.cbRequested)	r   ÚEventLoggingObserverr   ÚaddObserverr   rC   rk   r   rO   )r#   r   rN   rŽ   r   )rˆ   r‡   r|   rx   r#   r   Útest_requestHeaders·   s   
ÿ
z DistribTests.test_requestHeadersc                    ó8   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                   @   ó   e Zd Zdd„ ZdS )z>DistribTests.test_requestResponseCode.<locals>.SetResponseCodec                 S   s   |  d¡ dS )NéÈ   Ú ©ÚsetResponseCoderz   r   r   r   r}   à   s   
zEDistribTests.test_requestResponseCode.<locals>.SetResponseCode.renderNr~   r   r   r   r   ÚSetResponseCodeß   ó    r˜   c                    ó:   ˆ   | d jd¡ ˆ   | d jd¡ ˆ   | d jd¡ d S )Nr   ru   r0   r”   s   OK©rQ   ÚdataÚcodeÚphraserŒ   r>   r   r   rŽ   æ   ó   z:DistribTests.test_requestResponseCode.<locals>.cbRequested©r   rC   rt   rO   ©r#   r˜   rN   rŽ   r   r>   r   Útest_requestResponseCodeÙ   ó
   
z%DistribTests.test_requestResponseCodec                    r’   )z�
        The response code and message can be set by the request object passed to
        a distributed resource's C{render} method.
        c                   @   r“   )zEDistribTests.test_requestResponseCodeMessage.<locals>.SetResponseCodec                 S   s   |  dd¡ dS )Nr”   ó   some-messager•   r–   rz   r   r   r   r}   õ   s   zLDistribTests.test_requestResponseCodeMessage.<locals>.SetResponseCode.renderNr~   r   r   r   r   r˜   ô   r™   r˜   c                    rš   )Nr   ru   r0   r”   r¤   r›   rŒ   r>   r   r   rŽ   û   rŸ   zADistribTests.test_requestResponseCodeMessage.<locals>.cbRequestedr    r¡   r   r>   r   Útest_requestResponseCodeMessageî   r£   z,DistribTests.test_requestResponseCodeMessagec                 C   ó8   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                   @   r“   )z0DistribTests.test_largeWrite.<locals>.LargeWritec                 S   s    |  dt d ¡ | ¡  tjS ©Nó   xó   y)Úwriter   Úfinishr   ÚNOT_DONE_YETrz   r   r   r   r}     s   z7DistribTests.test_largeWrite.<locals>.LargeWrite.renderNr~   r   r   r   r   Ú
LargeWrite
  r™   r­   r¨   r©   ©r   rC   rk   rO   rQ   r   )r#   r­   rN   r   r   r   Útest_largeWrite  s   zDistribTests.test_largeWritec                 C   r¦   )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                   @   r“   )z2DistribTests.test_largeReturn.<locals>.LargeReturnc                 S   s   dt  d S r§   r   rz   r   r   r   r}     s   z9DistribTests.test_largeReturn.<locals>.LargeReturn.renderNr~   r   r   r   r   ÚLargeReturn  r™   r°   r¨   r©   r®   )r#   r°   rN   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@   ru   c                    sL   ˆ  ˆ jd¡ ˆ tj¡}ˆ  t|ƒd¡ g d¢}ˆ  d |¡gˆ j¡ d S )Niô  r0   )
ru   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>ru   ó   
)rQ   ÚresponseCodeÚflushLoggedErrorsr   ÚNoSuchMethodÚlenÚjoinÚwritten)ÚignoredÚerrorsÚexpected©rN   r#   r   r   Ú
cbRendered2  s
   z4DistribTests.test_connectionLost.<locals>.cbRendered)r   r   ÚRootr2   r   rH   r9   r   rI   rJ   rK   r4   r   r   rO   )r#   ÚserverFactoryÚ
serverPortÚsubscriptionrX   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.
        ru   r0   zFailure instancer   r€   N)r   r�   ÚcreateWithCleanupr   r	   ÚFailurer&   r   r   ÚIssueÚfailedÚassertEqualsr¶   r„   )r#   r‡   ÚfrN   Ú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.
        r0   r   Úlog_failureN)r   r�   rÃ   r   r&   r	   rÄ   r   ÚRequestr   Úfailr´   rÇ   r¶   ÚassertIs)r#   r‡   ÚerrrÈ   r|   r   r   r   Útest_requestFail]  s   ÿ


zDistribTests.test_requestFail)r   r   r   r9   r<   r4   r2   r?   rY   rf   rk   rt   r‘   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#   Úusersr   r   r   Ú__init__o  ó   
z_PasswordDatabase.__init__c                 C   s
   t | jƒS r    )ÚiterrÒ   r>   r   r   r   Úgetpwallr  rÕ   z_PasswordDatabase.getpwallc                 C   s&   | j D ]}|d |kr|  S qtƒ ‚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                   @   sl   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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Ñ   Údatabaser   ÚUserDirectoryÚ	directoryr>   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   Ú	IResourcerå   r>   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”  )rQ   r³   )r¹   r¼   r   r   r½   —  s   z/UserDirectoryTests._404Test.<locals>.cbRendered)r   rå   ÚgetChildr   rO   )r#   Únamer�   rX   r½   r   r¼   r   Ú_404TestŽ  s   


zUserDirectoryTests._404Testc                 C   ó
   |   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.
        Úcarol©rì   r>   r   r   r   Útest_getInvalidUser�  ó   
z&UserDirectoryTests.test_getInvalidUserc                 C   rí   )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ï   r>   r   r   r   Útest_getUserWithoutResource¥  rñ   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à   r]   Úmakedirsr   rå   rê   ÚassertIsInstancer   ÚFilerQ   Úpath)r#   Úhomerô   rN   r�   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.twistdÚunixN)r
   rõ   rà   rö   r]   r   rå   rê   r÷   r   rI   rQ   r\   r   rK   rù   )r#   rú   ÚwebrN   r�   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.
        r•   ÚPOSTN)r   ÚmethodÚassertRaisesr   ÚUnsupportedMethodrå   r}   rz   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ü   ru   r•   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 )	Nru   ÚliÚaÚhrefzalice/zAlice (file)zbob.twistd/zBob (twistd))	r   r·   r¸   ÚgetElementsByTagNamerQ   Ú
firstChildÚtagNameÚgetAttributerœ   )r¹   ÚdocumentrÝ   rà   r¼   r   r   r½   ä  s   z2UserDirectoryTests.test_render.<locals>.cbRendered)r
   rõ   rÝ   r]   rö   rà   Ú
setContentr   r   rå   rO   )r#   rô   rþ   r�   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ä   ÚassertIdenticalÚ_pwdÚpwd)r#   rå   r   r   r   Útest_passwordDatabaseó  s   z(UserDirectoryTests.test_passwordDatabaseN)r   r   r   r%   ræ   ré   rì   rð   rò   rû   rÿ   r  r  r   r  r  r   r   r   r   rÜ   |  s    	
 rÜ   )1r%   Úos.pathr   Úxml.dom.minidomr   r  r  ÚImportErrorÚunittestr   Úzope.interface.verifyr   Útwisted.internetr   r   Útwisted.loggerr   Útwisted.pythonr	   r
   Útwisted.spreadr   Útwisted.spread.bananar   Útwisted.testr   Útwisted.trial.unittestr   Útwisted.webr   r   r   r   r   Útwisted.web.http_headersr   Útwisted.web.test._utilr   Útwisted.web.test.test_webr   r   rF   r   r   Ú	Exceptionr&   r'   rÑ   rÜ   r   r   r   r   Ú<module>   s<   ÿ  3