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