Current File : //proc/self/root/lib/python3/dist-packages/twisted/test/__pycache__/test_twistd.cpython-312.pyc
�

Ϫ�f$!���dZddlZddlZddlZddlZddlZddlZ	ddlZddl	Z
e
Z	eZddlm
Z
ddlmZddlmZddlmZddlmZmZmZddlmZmZmZdd	lmZdd
lmZddl m!Z!ddl"m#Z#m$Z$dd
l%m&Z&ddl'm(Z(ddl)m*Z*m+Z+m,Z,ddl-m.Z.ddl/m0Z0ddl1m2Z2ddl3m*Z4m5Z5ddl6m7Z7ddl8m9Z9ddl:m;Z;ddl<m=Z=ddl>m?Z?ddl@mAZAe7d�ZBeBr
ddlCmDZDmEZEmFZFe7d�ZGe7d�ZHe7d�ZIe7d�ZJd �ZKGd!�d"�ZLGd#�d$ej��ZNGd%�d&e=j��ZPGd'�d(eA�ZQeeBd)�Gd*�d+eA��ZRGd,�d-eA�ZSGd.�d/�ZTGd0�d1ej��ZVGd2�d3eA�ZWeeBd)�Gd4�d5eA��ZXeeBd)�Gd6�d7eA��ZYeeBd)�Gd8�d9eA��ZZGd:�d;�Z[ee#�Gd<�d=e[��Z\Gd>�d?�Z]Gd@�dAeA�Z^dB�Z_dC�Z`GdD�dEeA�ZaeeBd)�GdF�dGeA��ZbeeBdH�GdI�dJeA��Zcee$�GdK�dLe(��ZdGdM�dNe=j��ZedO�ZfGdP�dQeA�Zgy#e$rdZ	dZY��awxYw)RzE
Tests for L{twisted.application.app} and L{twisted.scripts.twistd}.
�N)�StringIO)�skipIf)�implementer)�verifyObject)�internet�logger�plugin)�app�reactors�service)�
IServiceMaker)�ReactorBase)�Deferred)�IReactorDaemonize�_ISupportsExitSignalCapturing)�AlternateReactor)�
MemoryReactor)�ILogObserver�globalLogBeginner�globalLogPublisher)�util)�
Componentized)�UserDatabase)r�textFromEventDict)�
requireModule)�platformType)�
UsageError)�twistd)�MockOS)�TestCaseztwisted.scripts._twistd_unix)�UnixApplicationRunner�
UnixAppLogger�checkPIDztwisted.python.syslog�profile�pstats�cProfilec	������tjtj��}tjtj���t�}|j||j|�|j|j|j����fd�}|td|j�|td|�|td|j�y)au
    Patch L{pwd.getpwnam} so that it behaves as though only one user exists
    and patch L{grp.getgrnam} so that it behaves as though only one group
    exists.

    @param patch: A function like L{TestCase.patch} which will be used to
        install the fake implementations.

    @type user: C{str}
    @param user: The name of the single user which will exist.

    @type uid: C{int}
    @param uid: The UID of the single user which will exist.

    @type group: C{str}
    @param group: The name of the single user which will exist.

    @type gid: C{int}
    @param gid: The GID of the single group which will exist.
    c���t��}�||j�j�<�||j�j�<t	|�}�|i|S�N)�list�index�gr_name�gr_gid�tuple)�name�result�gid�grent�groups  ����:/usr/lib/python3/dist-packages/twisted/test/test_twistd.py�getgrnamz#patchUserDatabase.<locals>.getgrnamdsR����e���.3��v�|�|�E�M�M�*�+�-0��v�|�|�E�L�L�)�*��v����v��t�$�$��getpwnamr5�getpwuidN)�pwdr8�os�getuid�grp�getgrgid�getgidr�addUser�	pw_passwd�pw_gecos�pw_dir�pw_shellr7)	�patch�user�uidr3r1�pwent�databaser5r2s	   ``   @r4�patchUserDatabaserICs����2
�L�L�����%�E��L�L�����%�E��~�H�����e�o�o�s�C�������u�~�~��%�
�#�z�8�,�,�-�	�#�z�8�$�	�#�z�8�,�,�-r6c��eZdZdZdZd�Zy)�MockServiceMakerzO
    A non-implementation of L{twisted.application.service.IServiceMaker}.
    �ueoac�Z�||_tj�|_|jS)ze
        Take a L{usage.Options} instance and return a
        L{service.IService} provider.
        )�optionsr�Service��selfrNs  r4�makeServicezMockServiceMaker.makeServicews#��
������(����|�|�r6N)�__name__�
__module__�__qualname__�__doc__�tapnamerR�r6r4rKrKps����G�r6rKc��eZdZdZd�Zy)�CrippledAppLoggerz*
    @see: CrippledApplicationRunner.
    c��yr)rX�rQ�applications  r4�startzCrippledAppLogger.start����r6N)rSrTrUrVr^rXr6r4rZrZ�s���
r6rZc� �eZdZdZeZd�Zd�Zy)�CrippledApplicationRunnerz�
    An application runner that cripples the platform-specific runner and
    nasty side-effect-having code so that we can use it without actually
    running any environment-affecting code.
    c��yr)rX�rQs r4�preApplicationz(CrippledApplicationRunner.preApplication�r_r6c��yr)rXrcs r4�postApplicationz)CrippledApplicationRunner.postApplication�r_r6N)rSrTrUrVrZ�
loggerFactoryrdrfrXr6r4rara�s���&�M�
�
r6rac��eZdZdZd�Zd�Zd�Zd�Zd�Ze	e
d�d��Ze	e
d�d	��Ze	e
d�d
��Z
d�Zd�Zd
�Zd�Zy)�ServerOptionsTestszT
    Non-platform-specific tests for the platform-specific ServerOptions class.
    c�.���
���Gd�d�}|d��|d��
|d��|d����
���fd�}tj�}�j|jtj
�||_|j}��
��g}t||�D]w\}}|\}}	}
}�j||j��j|	��j|
�|j�f�j||j��yy)	zh
        subCommands is built from IServiceMaker plugins, and is sorted
        alphabetically.
        c��eZdZd�Zd�Zy)�7ServerOptionsTests.test_subCommands.<locals>.FakePluginc�:�||_d|z|_d|z|_y)Nzoptions for �description of )rW�_options�description�rQr/s  r4�__init__z@ServerOptionsTests.test_subCommands.<locals>.FakePlugin.__init__�s"��#��� .�� 5��
�#4�t�#;�� r6c��|jSr))rorcs r4rNz?ServerOptionsTests.test_subCommands.<locals>.FakePlugin.options�s���}�}�$r6N)rSrTrUrrrNrXr6r4�
FakePluginrl�s��
<�

%r6rt�apple�banana�coconut�donutc3�Z�K��j|t�������������y�wr))�assertEqualr
)�	interfacerurvrwrxrQs �����r4�
getPluginsz7ServerOptionsTests.test_subCommands.<locals>.getPlugins�s+��������Y�
�6��M��L��K��K�s�(+N)r�
ServerOptionsrz�_getPluginsr	r|�subCommands�ziprW�assertIsNonerorp)rQrtr|�configr�
expectedOrder�
subCommand�expectedCommandr/�shortcut�parserClass�
documentationrurvrwrxs`           @@@@r4�test_subCommandsz#ServerOptionsTests.test_subCommands�s���	%�	%��7�#���H�%���Y�'���7�#��	�	��%�%�'������+�+�V�->�->�?�'����(�(������7�
�+.�{�M�+J�	I�'�J��9C�6�D�(�K�����T�?�#:�#:�;����h�'����[�]�O�,D�,D�E�F����]�O�,G�,G�H�	Ir6c�\�����	�
��Gd�d�}|d��|d��|d��|d��	����	fd�}tj�}�j|jtj
�||_t
�|_�jt|jdg�|jj��
g�����	fD]-}�
��fd	�}||j�||j��/�j�t��d
j�
��y)zP
        Reactor names are listed alphabetically by I{--help-reactors}.
        c��eZdZd�Zy)�GServerOptionsTests.test_sortedReactorHelp.<locals>.FakeReactorInstallerc�:�d|z|_d|z|_d|_y)Nzname of rnztwisted.internet.default)�	shortNamerp�
moduleNamerqs  r4rrzPServerOptionsTests.test_sortedReactorHelp.<locals>.FakeReactorInstaller.__init__�s"��!+�d�!2���#4�t�#;�� �"<��r6N)rSrTrUrrrXr6r4�FakeReactorInstallerr��s��
=r6r�rurvrwrxc3�.�K�������������y�wr)rX)rurvrwrxs����r4�getReactorTypeszBServerOptionsTests.test_sortedReactorHelp.<locals>.getReactorTypes�s������M��L��K��K�s�z--help-reactorsc�j���j|���j�j|��yr))�assertIn�appendr+)�s�
helpOutput�indexesrQs ���r4�getIndexz;ServerOptionsTests.test_sortedReactorHelp.<locals>.getIndex�s(����
�
�a��,����z�/�/��2�3r6z9reactor descriptions were not in alphabetical order: {!r}N)rr}rz�_getReactorTypesrr�r�
messageOutput�assertRaises�
SystemExit�parseOptions�getvaluer�rp�sorted�format)rQr�r�r��reactorr�rurvrwrxr�r�s`     @@@@@@r4�test_sortedReactorHelpz)ServerOptionsTests.test_sortedReactorHelp�s���
	=�	=�%�W�-��%�h�/��&�y�1��$�W�-��	��%�%�'������0�0�(�2J�2J�K�"1���'�z������*�f�&9�&9�<M�;N�O��)�)�2�2�4�
����f�g�u�4�	*�G�
4�
�W�&�&�'��W�(�(�)�	*�	
�����7�O�G�N�N��
�	
r6c��tj�}d|_|j�|j	|d�y)zS
        postOptions should set no_save to True when a subcommand is used.
        rL�no_saveN)rr}r��postOptions�
assertTrue�rQr�s  r4�&test_postOptionsSubCommandCausesNoSavez9ServerOptionsTests.test_postOptionsSubCommandCausesNoSave�s7���%�%�'��"�����������y�)�*r6c�t�tj�}|j�|j|d�y)zR
        If no sub command is used, postOptions should not touch no_save.
        r�N)rr}r��assertFalser�s  r4�(test_postOptionsNoSubCommandSavesAsUsualz;ServerOptionsTests.test_postOptionsNoSubCommandSavesAsUsuals1���%�%�'����������	�*�+r6c��tj�}t|�}tjj
D]}|j
||��y)zq
        All the profilers that can be used in L{app.AppProfiler} are listed in
        the help output.
        N)rr}�strr
�AppProfiler�	profilersr�)rQr�r��profilers    r4�test_listAllProfilersz(ServerOptionsTests.test_listAllProfilers
sB��
�%�%�'����[�
����1�1�	0�H��M�M�(�J�/�	0r6�twistd unix not availablec�T�tj�}|j|d�y)zG
        The default value for the C{umask} option is L{None}.
        �umaskN)rr}r�r�s  r4�test_defaultUmaskz$ServerOptionsTests.test_defaultUmasks$��
�%�%�'�����&��/�*r6c���tj�}|jddg�|j|dd�|jddg�|j|dd�y)zh
        The value given for the C{umask} option is parsed as an octal integer
        literal.
        �--umask�123r��S�0123N)rr}r�rzr�s  r4�
test_umaskzServerOptionsTests.test_umasks`���%�%�'�����Y��.�/�������"�-����Y��/�0�������"�-r6c�r�tj�}|jt|jddg�y)z�
        If a value is given for the C{umask} option which cannot be parsed as
        an integer, L{UsageError} is raised by L{ServerOptions.parseOptions}.
        r��abcdefN)rr}r�rr�r�s  r4�test_invalidUmaskz$ServerOptionsTests.test_invalidUmask(s/���%�%�'�����*�f�&9�&9�I�x�;P�Qr6c�
�tj�}|jt|jddg�}|j|jdjd��|jd|jd�y)zQ
        C{--logger} with an unimportable module raises a L{UsageError}.
        �--loggerzno.such.module.I.hoperzeLogger 'no.such.module.I.hope' could not be imported: 'no.such.module.I.hope' does not name an object�
N�	rr}r�rr�r��args�
startswith�assertNotIn�rQr��es   r4�&test_unimportableConfiguredLogObserverz9ServerOptionsTests.test_unimportableConfiguredLogObserver1sy���%�%�'�������+�+�j�:Q�-R�
��	
���
�F�F�1�I� � �B�
�	
�	
����q�v�v�a�y�)r6c�
�tj�}|jt|jddg�}|j|jdjd��|jd|jd�y)zP
        C{--logger} with a non-existent object raises a L{UsageError}.
        r�ztwisted.test.test_twistd.FOOBARrz{Logger 'twisted.test.test_twistd.FOOBAR' could not be imported: module 'twisted.test.test_twistd' has no attribute 'FOOBAR'r�Nr�r�s   r4�*test_badAttributeWithConfiguredLogObserverz=ServerOptionsTests.test_badAttributeWithConfiguredLogObserverAsz���%�%�'���������
�:�;�
��
	
���
�F�F�1�I� � �,�
�	
�	
����q�v�v�a�y�)r6c�v�ddlm}tdk(rd}nd}dj||j|j�}t�}t
j|��}|jt|jdg�}|j|jd	�|j|j�|�y	)
z2
        C{--version} prints the version.
        r)�	copyright�win32z(the Twisted Windows runner)z(the Twisted daemon)ztwistd {} {}
{}
��stdoutz	--versionN)�twistedr�rr��versionrrr}r�r�r��assertIs�coderzr�)rQr�r/�expectedOutputr�r�r�s       r4�test_versionzServerOptionsTests.test_versionTs���	&��7�"�1�D�)�D�-�4�4��)�#�#�Y�%8�%8�
������%�%�V�4�����j�&�*=�*=��}�M���
�
�a�f�f�d�#�������*�N�;r6c��t�}tj|��}|jt|j
dg�y)zI
        Command is printed when an invalid option is requested.
        r�z	web --fooN)rrr}r�rr�)rQr�r�s   r4�!test_printSubCommandForUsageErrorz4ServerOptionsTests.test_printSubCommandForUsageErrorhs5������%�%�V�4�����*�f�&9�&9�K�=�Ir6N)rSrTrUrVr�r�r�r�r�r�_twistd_unixr�r�r�r�r�r�r�rXr6r4riri�s����)I�V-
�^+�,�0����9�:�+�;�+����9�:�	.�;�	.����9�:�R�;�R�*� *�&<�(Jr6rir�c�.�eZdZdZd�Zd�Zd�Zd�Zd�Zy)�
CheckPIDTestsz 
    Tests for L{checkPID}.
    c�^�|jtjdd��td�y)z7
        Nonexistent PID file is not an error.
        �existsc��y�NFrX)�_s r4�<lambda>z.CheckPIDTests.test_notExists.<locals>.<lambda>|��r6znon-existent PID fileN)rDr:�pathr#rcs r4�test_notExistszCheckPIDTests.test_notExistsxs!��	
�
�
�2�7�7�H�o�6��(�)r6c��|j�}t|d�5}|jd�ddd�|jtt
|�}|j
d|j�y#1swY�AxYw)zI
        Non-numeric content in a PID file causes a system exit.
        �wznon-numericNznon-numeric value)�mktemp�open�writer�r�r#r�r�)rQ�pidfile�fr�s    r4�test_nonNumericzCheckPIDTests.test_nonNumericsc���+�+�-��
�'�3�
�	#�1�
�G�G�M�"�	#����j�(�G�<���
�
�)�1�6�6�2�	#�	#�s�A/�/A8c�*�|j�}t|d�5}|jd�ddd�d�}|jtd|�|jtt|�}|jd|j�y#1swY�[xYw)zE
        Another running twistd server causes a system exit.
        r��42Nc��yr)rX��pid�sigs  r4�killz/CheckPIDTests.test_anotherRunning.<locals>.kill�s��r6r�zAnother twistd server)
r�r�r�rDr:r�r�r#r�r��rQr�r�r�r�s     r4�test_anotherRunningz!CheckPIDTests.test_anotherRunning�sy���+�+�-��
�'�3�
�	�1�
�G�G�D�M�	�	�	
�
�
�2�v�t�$����j�(�G�<���
�
�-�q�v�v�6�	�	�s�B	�	Bc�j�|j�}t|d�5}|jtt	j
�dz��ddd�d�}|j
td|�t|�|jtjj|��y#1swY�]xYw)zJ
        Stale PID file is removed without causing a system exit.
        r��Nc�6�ttjd���N�fake)�OSError�errno�ESRCHr�s  r4r�z&CheckPIDTests.test_stale.<locals>.kill�����%�+�+�v�.�.r6r�)r�r�r�r�r:�getpidrDr#r�r�r�)rQr�r�r�s    r4�
test_stalezCheckPIDTests.test_stale�s����+�+�-��
�'�3�
�	*�1�
�G�G�C��	�	��a��(�)�	*�	/�	
�
�
�2�v�t�$�������������0�1�	*�	*�s�0B)�)B2c��|j�}t|d�5}|jd�ddd�d�}|jtd|�|jtt|�}|j|jd�|j|jdjd��y#1swY��xYw)z�
        An unexpected L{OSError} when checking the validity of a
        PID in a C{pidfile} terminates the process via L{SystemExit}.
        r��3581Nc�6�ttjd��r��r�r��EBADFr�s  r4r�z2CheckPIDTests.test_unexpectedOSError.<locals>.kill�r�r6r�rzCan't check status of PID)
r�r�r�rDr:r�r�r#�assertIsNotr�r�r�r�r�s     r4�test_unexpectedOSErrorz$CheckPIDTests.test_unexpectedOSError�s���
�+�+�-��
�'�3�
�	�1�
�G�G�F�O�	�	/�	
�
�
�2�v�t�$����j�(�G�<���������&�������q�	�,�,�-H�I�J�	�	�s�B6�6B?N)	rSrTrUrVr�r�r�rrrXr6r4r�r�rs!���*�3�
7�
2�Kr6r�c��eZdZdZd�Zd�Zy)�TapFileTestszM
    Test twistd-related functionality that requires a tap file on disk.
    c���|j�|_t|jd�5}tjtjd�|�ddd�y#1swYyxYw)zP
        Create a trivial Application and put it in a tap file on disk.
        �wb�Hi!N)r��tapfiler��pickle�dumpr�Application)rQr�s  r4�setUpzTapFileTests.setUp�sO���{�{�}���
�$�,�,��
%�	7���K�K��+�+�E�2�A�6�	7�	7�	7�s�*A�A(c��tj�}|jd|jg�t	|�j�}|j
tj|�jd�y)z�
        Ensure that the createOrGetApplication call that 'twistd -f foo.tap'
        makes will load the Application out of foo.tap.
        z-frN)
rr}r�r
ra�createOrGetApplicationrzr�IServicer/)rQr�r]s   r4�&test_createOrGetApplicationWithTapFilez3TapFileTests.test_createOrGetApplicationWithTapFile�s]��
�%�%�'�����T�4�<�<�0�1�/��7�N�N�P������)�)�+�6�;�;�U�Cr6N)rSrTrUrVrrrXr6r4r	r	�s���7�Dr6r	c�"�eZdZdZd�Zd�Zd�Zy)�TestLoggerFactoryz8
    A logger factory for L{TestApplicationRunner}.
    c��||_yr))�runner)rQrs  r4rrzTestLoggerFactory.__init__�s	����r6c��|jjjd�t|jd�|j_y)zC
        Save the logging start on the C{runner} instance.
        �logr]N)r�orderr��hasattr�hadApplicationLogObserverr\s  r4r^zTestLoggerFactory.start�s3��	
����� � ��'�07����]�0S����-r6c��y)z%
        Don't log anything.
        NrXrcs r4�stopzTestLoggerFactory.stop�r�r6N)rSrTrUrVrrr^r rXr6r4rr�s����T�r6rc�"�eZdZdZd�Zd�Zd�Zy)�TestApplicationRunnerz`
    An ApplicationRunner which tracks the environment in which its methods are
    called.
    c�r�tjj||�g|_t	|�|_yr))r
�ApplicationRunnerrrrrrrPs  r4rrzTestApplicationRunner.__init__�s+�����&�&�t�W�5���
�'��-��r6c�\�|jjd�t|d�|_y)N�prer])rr�r�hadApplicationPreApplicationrcs r4rdz$TestApplicationRunner.preApplication�s#���
�
���%� �,3�D�-�,H��)r6c�\�|jjd�t|d�|_y)N�postr])rr�r�hadApplicationPostApplicationrcs r4rfz%TestApplicationRunner.postApplication�s#���
�
���&�!�-4�T�=�-I��*r6N)rSrTrUrVrrrdrfrXr6r4r"r"�s���
.�
I�Jr6r"c��eZdZdZd�Zd�Zd�Zd�Zee	e
dd�d�d	��Zee	e
dd�d�d
��Zd�Z
d�Zd
�Zd�Zy)�ApplicationRunnerTestszR
    Non-platform-specific tests for the platform-specific ApplicationRunner.
    c��tj�}t�|_d|ji|_t�|_d|_||_y)N�test_command)	rr}rK�serviceMaker�
loadedPlugins�object�
subOptionsr�r�r�s  r4rzApplicationRunnerTests.setUp�sG���%�%�'��,�.��� .��0A�0A�B���"�H���*�����r6c�f�t|j�}|j�|j|jj
|jjd�|j|jjtj|j�jdd�y)z�
        Ensure that a twistd plugin gets used in appropriate ways: it
        is passed its Options instance, and the service it returns is
        added to the application.
        zKServiceMaker.makeService needs to be passed the correct sub Command object.rzPServiceMaker.makeService's result needs to be set as a child of the Application.N)rar��runr�r/rNr2rrr]�services)rQ�arunners  r4�,test_applicationRunnerGetsCorrectApplicationzCApplicationRunnerTests.test_applicationRunnerGetsCorrectApplications���,�D�K�K�8�����
��
�
����%�%��K�K�"�"�
"�	
�	
�
�
����%�%����W�0�0�1�:�:�1�=�
"�	
r6c�,�t|j�}|j�|j|j�|j|j�|j|j�|j|jgd��y)z�
        Test thet preApplication and postApplication methods are
        called by ApplicationRunner.run() when appropriate.
        )r&rr)N)
r"r�r4r�r'r�r*rrzr)rQr�s  r4�test_preAndPostApplicationz1ApplicationRunnerTests.test_preAndPostApplicationsh��

"�$�+�+�.��	��������7�7�8�����7�7�8�����3�3�4�������"8�9r6c	���|jj|�g�G�fd�dtj�}t	t
jt
j�G�fd�d��}|�}tt
j|�tt
j|�||j�}|j�||_
|j�|j�dddd||fd	d
g�y)a.
        Assert that given a particular command line, an application is started
        as a particular UID/GID.

        @param argv: A list of strings giving the options to parse.
        @param uid: An integer giving the expected UID.
        @param gid: An integer giving the expected GID.
        c�2��eZdZ�fd�Z�fd�Z�fd�Zd�Zy)�\ApplicationRunnerTests._applicationStartsWithConfiguredID.<locals>.FakeUnixApplicationRunnerc�(���jd�y)N�environment�r�)rQ�chroot�rundir�nodaemonr�r��eventss      �r4�setupEnvironmentzmApplicationRunnerTests._applicationStartsWithConfiguredID.<locals>.FakeUnixApplicationRunner.setupEnvironment8s����
�
�m�,r6c�0���jd|||f�y)N�
privilegesr?)rQ�euidrFr1rCs    �r4�shedPrivilegeszkApplicationRunnerTests._applicationStartsWithConfiguredID.<locals>.FakeUnixApplicationRunner.shedPrivileges;s����
�
�|�T�3��<�=r6c�(���jd�y)Nr�r?)rQr��	oldstdout�	oldstderrrCs    �r4�startReactorziApplicationRunnerTests._applicationStartsWithConfiguredID.<locals>.FakeUnixApplicationRunner.startReactor>s����
�
�i�(r6c��yr)rX)rQr�s  r4�	removePIDzfApplicationRunnerTests._applicationStartsWithConfiguredID.<locals>.FakeUnixApplicationRunner.removePIDA���r6N)rSrTrUrDrHrLrN�rCs�r4�FakeUnixApplicationRunnerr<7s���
-�
>�
)�
r6rQc�R��eZdZdZdZdZdZdZdZd�Z	d�Z
d�Z�fd�Z�fd�Z
d�Zy)�NApplicationRunnerTests._applicationStartsWithConfiguredID.<locals>.FakeServiceNc��yr)rXrqs  r4�setNamezVApplicationRunnerTests._applicationStartsWithConfiguredID.<locals>.FakeService.setNameMrOr6c��yr)rX)rQ�parents  r4�setServiceParentz_ApplicationRunnerTests._applicationStartsWithConfiguredID.<locals>.FakeService.setServiceParentPrOr6c��yr)rXrcs r4�disownServiceParentzbApplicationRunnerTests._applicationStartsWithConfiguredID.<locals>.FakeService.disownServiceParentSrOr6c�(���jd�y)N�privilegedStartServicer?�rQrCs �r4r\zeApplicationRunnerTests._applicationStartsWithConfiguredID.<locals>.FakeService.privilegedStartServiceVs����
�
�6�7r6c�(���jd�y)N�startServicer?r]s �r4r_z[ApplicationRunnerTests._applicationStartsWithConfiguredID.<locals>.FakeService.startServiceYs����
�
�n�-r6c��yr)rXrcs r4�stopServicezZApplicationRunnerTests._applicationStartsWithConfiguredID.<locals>.FakeService.stopService\rOr6)rSrTrUrW�runningr/�processNamerFr1rUrXrZr\r_rarPs�r4�FakeServicerSDs?����F��G��D��K��C��C�
�
�
�
8�
.�
r6rdr>r\rFFr_r�N)
r�r�r�_SomeApplicationRunnerrrr�IProcessrrdr]rfrz)	rQ�argvrFr1rQrdr]rrCs	        @r4�"_applicationStartsWithConfiguredIDz9ApplicationRunnerTests._applicationStartsWithConfiguredID*s����	
��� � ��&���	��(E�(E�	�
�W�%�%�w�'7�'7�	8�	�	�
9�	�4"�m���W�%�%�{�3��W�%�%�{�3�*�4�;�;�7������(������ ������(��u�c�3�/���
�		
r6�setuidNz5Platform does not support --uid/--gid twistd options.c�^�d}d}|jdt|�dt|�g||�y)a
        L{postApplication} should change the UID and GID to the values
        specified as numeric strings by the configuration after running
        L{service.IService.privilegedStartService} and before running
        L{service.IService.startService}.
        �����--uid�--gidN)rhr�)rQrFr1s   r4�.test_applicationStartsWithConfiguredNumericIDszEApplicationRunnerTests.test_applicationStartsWithConfiguredNumericIDsss4�������/�/�
�c�#�h���S��2�C��	
r6c�t�d}d}d}d}t|j||||�|jd|d|g||�y)a

        L{postApplication} should change the UID and GID to the values
        specified as user and group names by the configuration after running
        L{service.IService.privilegedStartService} and before running
        L{service.IService.startService}.
        �foork�barrlrmrnN)rIrDrh)rQrErFr3r1s     r4�+test_applicationStartsWithConfiguredNameIDszBApplicationRunnerTests.test_applicationStartsWithConfiguredNameIDs�sJ�����������$�*�*�d�C���<��/�/�
�d�G�U�+�S�#�	
r6c��t�}tjdddd��}|j|dd�|j	|j
d�y)z7
        L{startReactor} calls L{reactor.run}.
        Fr$�r$r��debugNz'startReactor did not call reactor.run())�DummyReactorr
r$rLr��called�rQr�rs   r4�test_startReactorRunsTheReactorz6ApplicationRunnerTests.test_startReactorRunsTheReactor�sL���.���&�&��9�u�E�
��	���G�T�4�0�������(Q�Rr6c���t�}|jtd|�tjdddd��}|jddd�|j
|j�y)zN
        L{ApplicationRunner} chooses a reactor if none is specified.
        r�Fr$ruN)rwrDrr
r$rLr�rxrys   r4�*test_applicationRunnerChoosesReactorIfNonezAApplicationRunnerTests.test_applicationRunnerChoosesReactorIfNone�sY���.���
�
�8�Y��0��&�&��9�u�E�
��	���D�$��-�������'r6c��Gd�dt�}|�}tjdddd��}|j|dd�|j	d|j
�y)zg
        If the reactor exits with a signal, the application runner caches
        the signal.
        c��eZdZdZd�Zd�Zy)�[ApplicationRunnerTests.test_applicationRunnerCapturesSignal.<locals>.DummyReactorWithSignal��
            A dummy reactor, providing a C{run} method, and setting the
            _exitSignal attribute to a nonzero value.
            c��y�z=
                Dummy method, does nothing.
                NrXrcs r4�installWakerzhApplicationRunnerTests.test_applicationRunnerCapturesSignal.<locals>.DummyReactorWithSignal.installWaker�r�r6c��d|_y)zZ
                A fake run method setting _exitSignal to a nonzero value
                �N��_exitSignalrcs r4r4z_ApplicationRunnerTests.test_applicationRunnerCapturesSignal.<locals>.DummyReactorWithSignal.run�s��$%�� r6N�rSrTrUrVr�r4rXr6r4�DummyReactorWithSignalr�s��
�

�

%r6r�Fr$ruNr�)rr
r$rL�assertEqualsr�)rQr�r�rs    r4�$test_applicationRunnerCapturesSignalz;ApplicationRunnerTests.test_applicationRunnerCapturesSignal�s\��	%�[�	%�")�*���&�&��9�u�E�
��	���G�T�4�0����!�V�/�/�0r6c��Gd�d�}|�}tjdddd��}|j|dd�|jd|j�y)z�
        The runner sets its _exitSignal instance attribute to None if
        the reactor does not implement L{_ISupportsExitSignalCapturing}.
        c��eZdZdZd�Zd�Zy)�iApplicationRunnerTests.test_applicationRunnerIgnoresNoSignal.<locals>.DummyReactorWithExitSignalAttributer�c��yr�rXrcs r4r�zvApplicationRunnerTests.test_applicationRunnerIgnoresNoSignal.<locals>.DummyReactorWithExitSignalAttribute.installWaker�r�r6c��d|_y)z�
                A fake run method setting _exitSignal to a nonzero value
                that should be ignored.
                r�Nr�rcs r4r4zmApplicationRunnerTests.test_applicationRunnerIgnoresNoSignal.<locals>.DummyReactorWithExitSignalAttribute.run�s��
$%�� r6Nr�rXr6r4�#DummyReactorWithExitSignalAttributer��s��
�

�

%r6r�Fr$ruN)r
r$rLr�r�)rQr�r�rs    r4�%test_applicationRunnerIgnoresNoSignalz<ApplicationRunnerTests.test_applicationRunnerIgnoresNoSignal�sZ��	%�	%�$6�7���&�&��9�u�E�
��	���G�T�4�0����$�� 2� 2�3r6)rSrTrUrVrr7r9rhr�getattrr:rorsrzr|r�r�rXr6r4r,r,�s�����
�,
:�G
�R��B��$�'�'�?��
�	�
���B��$�'�'�?��
�	�
� 	S�
(�1�<4r6r,c�f�eZdZdZe�Zd�Zd�Zd�Zd�Z	d�Z
d�Zd�Zd	�Z
d
�Zd�Zd�Zd
�Zy)�*UnixApplicationRunnerSetupEnvironmentTestsa�
    Tests for L{UnixApplicationRunner.setupEnvironment}.

    @ivar root: The root of the filesystem, or C{unset} if none has been
        specified with a call to L{os.chroot} (patched for this TestCase with
        L{UnixApplicationRunnerSetupEnvironmentTests.chroot}).

    @ivar cwd: The current working directory of the process, or C{unset} if
        none has been specified with a call to L{os.chdir} (patched for this
        TestCase with L{UnixApplicationRunnerSetupEnvironmentTests.chdir}).

    @ivar mask: The current file creation mask of the process, or C{unset} if
        none has been specified with a call to L{os.umask} (patched for this
        TestCase with L{UnixApplicationRunnerSetupEnvironmentTests.umask}).

    @ivar daemon: A boolean indicating whether daemonization has been performed
        by a call to L{_twistd_unix.daemonize} (patched for this TestCase with
        L{UnixApplicationRunnerSetupEnvironmentTests}.
    c�����j�_�j�_�j�_d�_tj��_�jt
d�fd���jt
d�fd���jt
d�fd��ttj���_�j�j_
y)NFr@c���t�d|�S)N�root��setattr�r�rQs �r4r�zBUnixApplicationRunnerSetupEnvironmentTests.setUp.<locals>.<lambda>s���g�d�F�D�.I�r6�chdirc���t�d|�S)N�cwdr�r�s �r4r�zBUnixApplicationRunnerSetupEnvironmentTests.setUp.<locals>.<lambda>s���W�T�5�$�-G�r6r�c���t�d|�S)N�maskr�)r�rQs �r4r�zBUnixApplicationRunnerSetupEnvironmentTests.setUp.<locals>.<lambda>
s���W�T�6�4�-H�r6)�unsetr�r�r��daemonr:r�r�rDr!rr}r�	daemonizercs`r4rz0UnixApplicationRunnerSetupEnvironmentTests.setUps�����J�J��	��:�:����J�J��	�����9�9�;����
�
�2�x�!I�J��
�
�2�w� G�H��
�
�2�w� H�I�+�F�,@�,@�,B�C��� $������r6c�H��d�_�jtd�fd��y)z�
        Indicate that daemonization has happened and change the PID so that the
        value written to the pidfile can be tested in the daemonization case.
        Tr�c�"���jdzS�Nr�)r�rcs�r4r�zFUnixApplicationRunnerSetupEnvironmentTests.daemonize.<locals>.<lambda>s������A��r6N)r�rDr:�rQr�s` r4r�z4UnixApplicationRunnerSetupEnvironmentTests.daemonizes���
����
�
�2�x�!5�6r6c�z�|jjddddd�|j|jd�y)z�
        L{UnixApplicationRunner.setupEnvironment} changes the root of the
        filesystem if passed a non-L{None} value for the C{chroot} parameter.
        �/foo/bar�.TN)rrDrzr�rcs r4�test_chrootz6UnixApplicationRunnerSetupEnvironmentTests.test_chroots2��
	
���$�$�Z��d�D�$�G�������J�/r6c��|jjddddd�|j|j|j�y)z�
        L{UnixApplicationRunner.setupEnvironment} does not change the root of
        the filesystem if passed L{None} for the C{chroot} parameter.
        Nr�T)rrDr�r�r�rcs r4�
test_noChrootz8UnixApplicationRunnerSetupEnvironmentTests.test_noChroot!s4��
	
���$�$�T�3��d�D�A��
�
�d�i�i����,r6c�z�|jjddddd�|j|jd�y)z�
        L{UnixApplicationRunner.setupEnvironment} changes the working directory
        of the process to the path given for the C{rundir} parameter.
        Nr�T)rrDrzr�rcs r4�test_changeWorkingDirectoryzFUnixApplicationRunnerSetupEnvironmentTests.test_changeWorkingDirectory)s2��
	
���$�$�T�:�t�T�4�H�������:�.r6c���tt��5|jjddddd�ddd�|j	|j
�y#1swY�%xYw)z�
        L{UnixApplicationRunner.setupEnvironment} daemonizes the process if
        C{False} is passed for the C{nodaemon} parameter.
        Nr�F)r�FakeDaemonizingReactorrrDr�r�rcs r4�test_daemonizez9UnixApplicationRunnerSetupEnvironmentTests.test_daemonize1sS��
�4�6�
7�	G��K�K�(�(��s�E�4��F�	G�������$�	G�	G�s� A�A!c�x�|jjddddd�|j|j�y)z�
        L{UnixApplicationRunner.setupEnvironment} does not daemonize the
        process if C{True} is passed for the C{nodaemon} parameter.
        Nr�T)rrDr�r�rcs r4�test_noDaemonizez;UnixApplicationRunnerSetupEnvironmentTests.test_noDaemonize:s0��
	
���$�$�T�3��d�D�A�������%r6c��|j�}|jjdddd|�t|d�5}t	|j��}ddd�|j
|j�y#1swY�&xYw)z�
        L{UnixApplicationRunner.setupEnvironment} writes the process's PID to
        the file specified by the C{pidfile} parameter.
        Nr�T�rb)r�rrDr��int�readrzr��rQr�r�r�s    r4�test_nonDaemonPIDFilez@UnixApplicationRunnerSetupEnvironmentTests.test_nonDaemonPIDFileBsm��
�+�+�-�����$�$�T�3��d�G�D�
�'�4�
 �	 �A��a�f�f�h�-�C�	 �����d�h�h�'�	 �	 �s�A;�;Bc�d�|j�}tt��5|jj	dddd|�ddd�t|d�5}t
|j��}ddd�|j|jdz�y#1swY�WxYw#1swY�5xYw)z�
        L{UnixApplicationRunner.setupEnvironment} writes the daemonized
        process's PID to the file specified by the C{pidfile} parameter if
        C{nodaemon} is C{False}.
        Nr�Fr�r�)
r�rr�rrDr�r�r�rzr�r�s    r4�test_daemonPIDFilez=UnixApplicationRunnerSetupEnvironmentTests.test_daemonPIDFileMs����+�+�-��
�4�6�
7�	J��K�K�(�(��s�E�4��I�	J�
�'�4�
 �	 �A��a�f�f�h�-�C�	 �����d�h�h��l�+�		J�	J��	 �	 �s� B�B&�B#�&B/c���tt��5|jjddddd�ddd�|j	|j
d�y#1swY�&xYw)z�
        L{UnixApplicationRunner.setupEnvironment} changes the process umask to
        the value specified by the C{umask} parameter.
        Nr�F�{�rr�rrDrzr�rcs r4r�z5UnixApplicationRunnerSetupEnvironmentTests.test_umaskZsW��
�4�6�
7�	F��K�K�(�(��s�E�3��E�	F�������C�(�	F�	F��� A�A"c��|jjddddd�|j|j|j�y)z�
        L{UnixApplicationRunner.setupEnvironment} doesn't change the process
        umask if L{None} is passed for the C{umask} parameter and C{True} is
        passed for the C{nodaemon} parameter.
        Nr�T)rrDr�r�r�rcs r4�test_noDaemonizeNoUmaskzBUnixApplicationRunnerSetupEnvironmentTests.test_noDaemonizeNoUmaskcs4��	
���$�$�T�3��d�D�A��
�
�d�i�i����,r6c���tt��5|jjddddd�ddd�|j	|j
d�y#1swY�&xYw)z�
        L{UnixApplicationRunner.setupEnvironment} changes the process umask to
        C{0077} if L{None} is passed for the C{umask} parameter and C{False} is
        passed for the C{nodaemon} parameter.
        Nr�F�?r�rcs r4�test_daemonizedNoUmaskzAUnixApplicationRunnerSetupEnvironmentTests.test_daemonizedNoUmasklsW���4�6�
7�	G��K�K�(�(��s�E�4��F�	G�������E�*�	G�	G�r�N)rSrTrUrVr1r�rr�r�r�r�r�r�r�r�r�r�r�rXr6r4r�r��sL���(
�H�E�
/�7�0�-�/�%�&�	(�,�)�-�+r6r�c�4�eZdZdZd�Zd�Zd�Zd�Zd�Zd�Z	y)	�*UnixApplicationRunnerStartApplicationTestsz>
    Tests for L{UnixApplicationRunner.startApplication}.
    c���tj�}|jgd��tjd�}t|�|_g��fd�}tj|jj�j}tj|�j}|j�}|jd�|j||�|jt
d|�|jt
dd��|jtdd	��|jj!|�|j�gd
��y)z�
        L{UnixApplicationRunner.startApplication} calls
        L{UnixApplicationRunner.setupEnvironment} with the chroot, rundir,
        nodaemon, umask, and pidfile parameters from the configuration it is
        constructed with.
        )	�
--nodaemonr��0070z--chroot�/foo/chrootz--rundir�/foo/rundir�	--pidfile�/foo/pidfile�test_setupEnvironmentc�2���j|||||f�yr))�extend)rQr@rArBr�r�r�s      �r4�fakeSetupEnvironmentz^UnixApplicationRunnerStartApplicationTests.test_setupEnvironment.<locals>.fakeSetupEnvironment�s����K�K����5�'�B�Cr6rQrDrHc��yr)rX��a�kws  r4r�zRUnixApplicationRunnerStartApplicationTests.test_setupEnvironment.<locals>.<lambda>�r�r6�startApplicationc��yr)rXr�s  r4r�zRUnixApplicationRunnerStartApplicationTests.test_setupEnvironment.<locals>.<lambda>�r�r6)r�r�T�8r�N)rr}r�rrr!r�inspect�	signaturerD�
parameters�copy�poprzrDr
r�)rQrNr]r��setupEnvironmentParameters�fakeSetupEnvironmentParametersr�s      @r4r�z@UnixApplicationRunnerStartApplicationTests.test_setupEnvironment}s!����&�&�(�����

�	
��)�)�*A�B��+�G�4�����	D�&-�%6�%6��K�K�(�(�&
�
�*�	#�*1�):�):� �*
�
�*�	'�*H�)L�)L�)N�&�&�*�*�6�2����3�5S�T��
�
�(�*<�>R�S��
�
�(�*:�<Q�R��
�
�3�*�,A�B����$�$�[�1�����W�Xr6c�z���fd�}�jtd|�ti�}|jddd�y)zf
        L{UnixApplicationRunner.shedPrivileges} switches the user ID
        of the process.
        c�r���j|d��j|d��j|d�y)N���6�#�rz)rFr1rGrQs   �r4�
switchUIDPasszUUnixApplicationRunnerStartApplicationTests.test_shedPrivileges.<locals>.switchUIDPass�s3������S�#�&����S�"�%����T�2�&r6�	switchUIDr�r�r�N)rDr�r!rH)rQr�rs`  r4�test_shedPrivilegesz>UnixApplicationRunnerStartApplicationTests.test_shedPrivileges�s6���	'�
	
�
�
�<��m�<�&�r�*�����b�#�r�*r6c���d�}ti�}|jtd|�|jt|j
ddd�}|j
|jd�y)z�
        An unexpected L{OSError} when calling
        L{twisted.scripts._twistd_unix.shedPrivileges}
        terminates the process via L{SystemExit}.
        c�6�ttjd��r�r)rFr1rGs   r4�
switchUIDFailzZUnixApplicationRunnerStartApplicationTests.test_shedPrivilegesError.<locals>.switchUIDFail�r�r6r�r�r�Nr�)r!rDr�r�r�rHrzr�)rQr�r�excs    r4�test_shedPrivilegesErrorzCUnixApplicationRunnerStartApplicationTests.test_shedPrivilegesError�sU��	/�'�r�*���
�
�<��m�<����
�F�,A�,A�2�s�D�Q��������1�%r6c������t�j|�|�����fd�}��fd�}��fd�}�jtd|��jtd|��jtd|�t	j
�}	|	j
ddt��d	|g�tjd
�}
t|	��_t|	�}|j|
�y)zj
        Common code for tests which try to pass the the UID to
        L{UnixApplicationRunner}.
        c�N���j|���j|��yr)r�)rFr1rQ�	wantedGid�	wantedUids  ���r4�
initgroupszFUnixApplicationRunnerStartApplicationTests._setUID.<locals>.initgroups�s#������S�)�,����S�)�,r6c�*���j|��yr)r�)rFrQr�s ��r4rizBUnixApplicationRunnerStartApplicationTests._setUID.<locals>.setuid��������S�)�,r6c�*���j|��yr)r�)r1rQr�s ��r4�setgidzBUnixApplicationRunnerStartApplicationTests._setUID.<locals>.setgid�r�r6r�rir�r�rmr�r�N)
rIrDrr:rr}r�r�rrr!rr�)rQ�
wantedUserr��wantedGroupr��pidFiler�rir�rNr]rs` ` `       r4�_setUIDz2UnixApplicationRunnerStartApplicationTests._setUID�s����
	�$�*�*�j�)�[�)�T�	-�	-�	-�	
�
�
�4��z�2��
�
�2�x��(��
�
�2�x��(��&�&�(�����
�7�C�	�N�K��I�	
��)�)�*A�B��+�G�4���&�w�/������,r6c�P�|jdddd|j�dz�y)z�
        Starting an application with L{UnixApplicationRunner} configured
        with a UID and no GUID will result in the GUID being
        set to the default GUID for that UID.
        rqirri�z_test_setUidWithoutGid.pidN)r�r�rcs r4�test_setUidWithoutGidz@UnixApplicationRunnerStartApplicationTests.test_setUidWithoutGid�s'��	
����4���d�k�k�m�6R�&R�	
r6c��tj�}|jd|ddd�|j�}dj	||�}|j||dd�|jdt
|�|�y	)
zz
        If the specified UID is the same as the current UID of the process,
        then a warning is displayed.
        �morefoo�morebari�ztest_setUidSameAsCurrentUid.pidz\tried to drop privileges and setuid {} but uid is already {}; should we be root? Continuing.r�messager�N)r:r;r��
flushWarningsr�rz�len)rQ�
currentUid�
warningsShown�expectedWarnings    r4�test_setUidSameAsCurrentUidzFUnixApplicationRunnerStartApplicationTests.test_setUidSameAsCurrentUid�s���
�Y�Y�[�
�����z�9�d�4U�	
��*�*�,�
�
-�-3�V�J�
�-K�	�	
����-��*:�9�*E�F�����C�
�.�
�>r6N)
rSrTrUrVr�r�r�r�r�rrXr6r4r�r�ws'���2Y�h
+�
&�-�<
�?r6r�c��eZdZdZd�Zd�Zy)�#UnixApplicationRunnerRemovePIDTestsz7
    Tests for L{UnixApplicationRunner.removePID}.
    c�V�ti�}|j�}tj|�tjj|d�}t
|d�j�|j|�|jtjj|��y)zp
        L{UnixApplicationRunner.removePID} deletes the file the name of
        which is passed to it.
        zfoo.pidr�N)r!r�r:�makedirsr��joinr��closerNr�r�)rQrr�r�s    r4�test_removePIDz2UnixApplicationRunnerRemovePIDTests.test_removePIDsu��
'�r�*���{�{�}��
���D���'�'�,�,�t�Y�/���W�c�� � �"�����!����������0�1r6c�
�ti�}|jd�|jt�}|j	t|�d�|j	|djjtj�y)zr
        Calling L{UnixApplicationRunner.removePID} with a non-existent filename
        logs an OSError.
        �fakepidr�rN)	r!rN�flushLoggedErrorsr�rzr�valuer��ENOENT)rQr�errorss   r4�test_removePIDErrorsz8UnixApplicationRunnerRemovePIDTests.test_removePIDErrorssb��
'�r�*������#��'�'��0������V��a�(���������.�.����=r6N)rSrTrUrVrrrXr6r4r	r	
s���2�	>r6r	c�(�eZdZdZd�Zd�Zd�Zd�Zy)�FakeNonDaemonizingReactora�
    A dummy reactor, providing C{beforeDaemonize} and C{afterDaemonize}
    methods, but not announcing this, and logging whether the methods have been
    called.

    @ivar _beforeDaemonizeCalled: if C{beforeDaemonize} has been called or not.
    @type _beforeDaemonizeCalled: C{bool}
    @ivar _afterDaemonizeCalled: if C{afterDaemonize} has been called or not.
    @type _afterDaemonizeCalled: C{bool}
    c� �d|_d|_yr�)�_beforeDaemonizeCalled�_afterDaemonizeCalledrcs r4rrz"FakeNonDaemonizingReactor.__init__5s��&+��#�%*��"r6c��d|_y�NT)rrcs r4�beforeDaemonizez)FakeNonDaemonizingReactor.beforeDaemonize9s
��&*��#r6c��d|_yr)rrcs r4�afterDaemonizez(FakeNonDaemonizingReactor.afterDaemonize<s
��%)��"r6c��y)z*
        Skip event registration.
        NrX)rQr�r�s   r4�addSystemEventTriggerz/FakeNonDaemonizingReactor.addSystemEventTrigger?r�r6N)rSrTrUrVrrrrr!rXr6r4rr)s��	�+�+�*�r6rc��eZdZdZy)r�z�
    A dummy reactor, providing C{beforeDaemonize} and C{afterDaemonize}
    methods, announcing this, and logging whether the methods have been called.
    N)rSrTrUrVrXr6r4r�r�Es��r6r�c��eZdZdZdZd�Zy)rwz�
    A dummy reactor, only providing a C{run} method and checking that it
    has been called.

    @ivar called: if C{run} has been called or not.
    @type called: C{bool}
    Fc�@�|jrtd��d|_y)zV
        A fake run method, checking that it's been called one and only time.
        zAlready calledTN)rx�RuntimeErrorrcs r4r4zDummyReactor.runXs���;�;��/�0�0���r6N)rSrTrUrVrxr4rXr6r4rwrwMs����F�r6rwc���eZdZdZeed�d��Zd�Zeed�d��Zd�Z	eed�d��Z
eed�d	��Zeed�d
��Z
d�Zd�Zd
�Zd�Zy)�AppProfilingTestsz'
    Tests for L{app.AppProfiler}.
    zprofile module not availablec��tj�}|j�|d<d|d<tj|�}t�}|j
|�|j|j�t|d�5}|j�}ddd�|jd�|jd|�y#1swY�.xYw)z�
        L{app.ProfileRunner.run} should call the C{run} method of the reactor
        and save profile data in the specified file.
        r$r�NzDummyReactor.run�function calls�rr}r�r
r�rwr4r�rxr�r�r��rQr�r�r�r��datas      r4�test_profilezAppProfilingTests.test_profilefs����%�%�'�� �K�K�M��y��&��z���?�?�6�*���.�����W��������'�
�&��#�
$�	���6�6�8�D�	��
�
�(�$�/��
�
�&��-�	�	���C�C
c��t�}|jtd|�}||�}|j�|j	�|j�}|j
d|�|j
d|�y)Nr�r)z(run))rrD�sys�print_stats�restorer�r�)rQ�
statsClassr$�outr��statsr,s       r4�
_testStatszAppProfilingTests._testStatszsg���j�����C��3�/���7�#��
���������|�|�~���
�
�&��-��
�
�g�t�$r6c�B�tj�}|j�|d<d|d<d|d<tj|�}t�}|j
|�|j|j�|jtj|d�y)z�
        With the C{savestats} option specified, L{app.ProfileRunner.run}
        should save the raw stats object instead of a summary output.
        r$r�T�	savestatsN�rr}r�r
r�rwr4r�rxr6r%�Stats�rQr�r�r�s    r4�test_profileSaveStatsz'AppProfilingTests.test_profileSaveStats�s~���%�%�'�� �K�K�M��y��&��z��"��{���?�?�6�*���.�����W��������'�������f�Y�&7�8r6c��tjj�}tj�}d|d<tj|�}dtjd<	|jt|jd�tjj�tjj|�y#tjj�tjj|�wxYw)z�
        When the C{profile} module is not present, L{app.ProfilerRunner.run}
        should raise a C{SystemExit} exception.
        r$r�N�r0�modulesr�rr}r
r�r�r�r4�clear�update�rQ�savedModulesr�r�s    r4�test_withoutProfilez%AppProfilingTests.test_withoutProfile�s���
�{�{�'�'�)���%�%�'��&��z���?�?�6�*��!%����I��	-����j�(�,�,��=��K�K�����K�K���|�,��
�K�K�����K�K���|�,���!!C�?C?c��Gd�dtj�}|jtd|�tj�}|j�|d<d|d<t
j|�}t�}tj}|jt|j|�|jtj|�y)z�
        When an error happens during the print of the stats, C{sys.stdout}
        should be restored to its initial value.
        c��eZdZd�Zy)�GAppProfilingTests.test_profilePrintStatsError.<locals>.ErroneousProfilec��td��)N�Boom�r%rcs r4r1zSAppProfilingTests.test_profilePrintStatsError.<locals>.ErroneousProfile.print_stats�s
��"�6�*�*r6N)rSrTrUr1rXr6r4�ErroneousProfilerH�s��
+r6rL�Profiler$r�N)r$rMrDrr}r�r
r�rwr0r�r�r%r4r�)rQrLr�r�r��	oldStdouts      r4�test_profilePrintStatsErrorz-AppProfilingTests.test_profilePrintStatsError�s���	+�w���	+�	
�
�
�7�I�'7�8��%�%�'�� �K�K�M��y��&��z���?�?�6�*���.���J�J�	����,����g�>��
�
�c�j�j�)�,r6zcProfile module not availablec��tj�}|j�|d<d|d<tj|�}t�}|j
|�|j|j�t|d�5}|j�}ddd�|jd�|jd|�y#1swY�.xYw)z�
        L{app.CProfileRunner.run} should call the C{run} method of the
        reactor and save profile data in the specified file.
        r$r&r�Nr4r)r*r+s      r4�
test_cProfilezAppProfilingTests.test_cProfile�s����%�%�'�� �K�K�M��y��'��z���?�?�6�*���.�����W��������'�
�&��#�
$�	���6�6�8�D�	��
�
�e�T�"��
�
�&��-�	�	�r.c�B�tj�}|j�|d<d|d<d|d<tj|�}t�}|j
|�|j|j�|jtj|d�y)z�
        With the C{savestats} option specified,
        L{app.CProfileRunner.run} should save the raw stats object
        instead of a summary output.
        r$r&r�Tr8Nr9r;s    r4�test_cProfileSaveStatsz(AppProfilingTests.test_cProfileSaveStats�s~���%�%�'�� �K�K�M��y��'��z��"��{���?�?�6�*���.�����W��������'�������f�Y�&7�8r6c��tjj�}dtjd<tj�}d|d<tj|�}	|jt|jd�tjj�tjj|�y#tjj�tjj|�wxYw)z�
        When the C{cProfile} module is not present,
        L{app.CProfileRunner.run} should raise a C{SystemExit}
        exception and log the C{ImportError}.
        Nr&r�r>rBs    r4�test_withoutCProfilez&AppProfilingTests.test_withoutCProfile�s����{�{�'�'�)��"&����J���%�%�'��'��z���?�?�6�*��	-����j�(�,�,��=��K�K�����K�K���|�,��
�K�K�����K�K���|�,�rEc���tj�}|j�|d<d|d<|jtt
j|�}|jt|�d�y)zq
        Check that L{app.AppProfiler} raises L{SystemExit} when given an
        unknown profiler name.
        r$�foobarr�z!Unsupported profiler name: foobarN)	rr}r�r�r�r
r�rzr�)rQr��errors   r4�test_unknownProfilerz&AppProfilingTests.test_unknownProfiler�sY��
�%�%�'�� �K�K�M��y��%��z���!�!�*�c�o�o�v�F������U��%H�Ir6c�f�tji�}|j|jd�y)zU
        L{app.Profiler} defaults to the cprofile profiler if not specified.
        �cprofileN�r
r�rzr��rQr�s  r4�test_defaultProfilerz&AppProfilingTests.test_defaultProfilers(���?�?�2�&������*�*�J�7r6c�j�tjddi�}|j|jd�y)ze
        The case of the profiler name passed to L{app.AppProfiler} is not
        relevant.
        r��CprOfiler[Nr\r]s  r4�test_profilerNameCaseInsentivez0AppProfilingTests.test_profilerNameCaseInsentives-��
�?�?�J�
�#;�<������*�*�J�7r6N)rSrTrUrVrr$r-r6r<rDrOr&rQrSrUrYr^rarXr6r4r'r'as������K�7�8�.�9�.�&%�"��K�7�8�9�9�9�"-�$��K�7�8�-�9�-�,��L�9�:�.�;�.�&��L�9�:�9�;�9�$-�$
J�8�8r6r'c�V���g�tj���fd�}|td|��S)a
    Patch L{logger.textFileLogObserver} to record every call and keep a
    reference to the passed log file for tests.

    @param patch: a callback for patching (usually L{TestCase.patch}).

    @return: the list that keeps track of the log files.
    @rtype: C{list}
    c�>���j|��|g|��i|��Sr)r?)�logFiler��kwargs�logFiles�oldFileLogObservers   ��r4�observerz+_patchTextFileLogObserver.<locals>.observer(s$������� �!�'�;�D�;�F�;�;r6�textFileLogObserver)rri)rDrhrfrgs  @@r4�_patchTextFileLogObserverrjs/����H��3�3��<�
�&�'��2��Or6c�R��g�G�fd�d�}|jtd|��S)zu
    Make fake syslog, and return list to which prefix and then log
    messages will be appended if it is used.
    c�"��eZdZ�fd�Z�fd�Zy)�(_setupSyslog.<locals>.fakesyslogobserverc�(���j|�yr)r?)rQ�prefix�logMessagess  �r4rrz1_setupSyslog.<locals>.fakesyslogobserver.__init__8s������v�&r6c�(���j|�yr)r?)rQ�	eventDictrps  �r4�emitz-_setupSyslog.<locals>.fakesyslogobserver.emit;s������y�)r6N)rSrTrUrrrs)rps�r4�fakesyslogobserverrm7s
���	'�	*r6rt�SyslogObserver)rD�syslog)�testCasertrps  @r4�_setupSyslogrx0s.���
�K�*�*�
�N�N�6�+�-?�@��r6c���eZdZdZd�Zd�Zd�Zd�Zd�Zd�Z	ie
jfd�Zd	�Z
d
�Zd�Zd�Zeed
�eed�d���Zd�Zd�Zd�Zd�Zd�Zd�Zy)�AppLoggerTestsz�
    Tests for L{app.AppLogger}.

    @ivar observers: list of observers installed during the tests.
    @type observers: C{list}
    c�L��g�_�fd�}�jtd|�y)z�
        Override L{globaLogBeginner.beginLoggingTo} so that we can trace the
        observers installed in C{self.observers}.
        c�t��|D]2}�jj|�tj|��4yr))�	observersr�r�addObserver)r}rhrQs  �r4�beginLoggingToz,AppLoggerTests.setUp.<locals>.beginLoggingToQs2���%�
9�����%�%�h�/�"�.�.�x�8�
9r6rN)r}rDr)rQrs` r4rzAppLoggerTests.setUpJs%���
���	9�
	
�
�
�$�&6��Gr6c�P�|jD]}tj|��y)z1
        Remove all installed observers.
        N)r}r�removeObserver�rQrhs  r4�tearDownzAppLoggerTests.tearDownXs%�����	8�H��-�-�h�7�	8r6c�H�tt�Gd�d��}|�S)z�
        Make a new observer which captures all logs sent to it.

        @return: An observer that stores all logs sent to it.
        @rtype: Callable that implements L{ILogObserver}.
        c��eZdZgZd�Zy)�2AppLoggerTests._makeObserver.<locals>.TestObserverc�:�|jj|�yr))�_logsr�)rQ�events  r4�__call__z;AppLoggerTests._makeObserver.<locals>.TestObserver.__call__ks���
�
�!�!�%�(r6N)rSrTrUr�r�rXr6r4�TestObserverr�gs���E�
)r6r�)rr)rQr�s  r4�
_makeObserverzAppLoggerTests._makeObserver_s*��
�\�	"�	)�	)�
#�	)��~�r6c���|j|j|g�|jd|jdd�|jd|jdd�y)z�
        Ensure that initial C{twistd} logs are written to logs.

        @param observer: The observer made by L{self._makeObserver).
        �starting upr�
log_formatz
reactor classr�N)rzr}r�r�r�s  r4�_checkObserverzAppLoggerTests._checkObserverpsR��	
������(��4��
�
�m�X�^�^�A�%6�|�%D�E��
�
�o�x�~�~�a�'8��'F�Gr6c���tji�}|j���fd�|_|jt��|j
��y)z�
        L{app.AppLogger.start} calls L{globalLogBeginner.addObserver}, and then
        writes some messages about twistd and the reactor.
        c����Sr)rX�rhs�r4r�z+AppLoggerTests.test_start.<locals>.<lambda>�s����r6N)r
�	AppLoggerr��_getLogObserverr^rr�)rQrrhs  @r4�
test_startzAppLoggerTests.test_startzsG���
���r�"���%�%�'��!1�������]�_�%����H�%r6c���t�}|j�}|jt|�t	j
i�}|j|�|j|�y)z�
        When the L{ILogObserver} component is available on the application,
        that object will be used as the log observer instead of constructing a
        new one.
        N)rr��setComponentrr
r�r^r�)rQr]rhrs    r4�$test_startUsesApplicationLogObserverz3AppLoggerTests.test_startUsesApplicationLogObserver�sS��$�o���%�%�'��� � ��x�8����r�"������[�!����H�%r6c���|j��d�fd�i}|j|�||�}|j|��S)a
        Set up an AppLogger which exercises the C{logger} configuration option.

        @type application: L{Componentized}
        @param application: The L{Application} object to pass to
            L{app.AppLogger.start}.
        @type extraLogArgs: C{dict}
        @param extraLogArgs: extra values to pass to AppLogger.
        @type appLogger: L{AppLogger} class, or a subclass
        @param appLogger: factory for L{AppLogger} instances.

        @rtype: C{list}
        @return: The logs accumulated by the log observer.
        rc����Sr)rXr�s�r4r�z7AppLoggerTests._setupConfiguredLogger.<locals>.<lambda>�s���X�r6)r�rAr^)rQr]�extraLogArgs�	appLogger�logArgsrrhs      @r4�_setupConfiguredLoggerz%AppLoggerTests._setupConfiguredLogger�sG���"�%�%�'���-�.�����|�$��7�#������[�!��r6c�X�t�}|j|j|��y)a
        When the C{logger} key is specified in the configuration dictionary
        (i.e., when C{--logger} is passed to twistd), the initial log observer
        will be the log observer returned from the callable which the value
        refers to in FQPN form.
        N)rr�r�r\s  r4�#test_startUsesConfiguredLogObserverz2AppLoggerTests.test_startUsesConfiguredLogObserver�s$��$�o�����D�7�7��D�Er6c���|j�}t�}|jt|�|j	|j|��|j
|jg�y)zk
        C{--logger} takes precedence over a L{ILogObserver} component set on
        Application.
        N)r�rr�rr�r�rzr�)rQrhr]s   r4�(test_configuredLogObserverBeatsComponentz7AppLoggerTests.test_configuredLogObserverBeatsComponent�sV��
�%�%�'��#�o��� � ��x�8����D�7�7��D�E��������,r6c��g}t�}|jt|j�|j	|j|��|j
|g�y)zq
        C{--logger} takes precedence over a L{LegacyILogObserver} component
        set on Application.
        N)rr��LegacyILogObserverr�r�r�rz)rQ�nonlogsr]s   r4�.test_configuredLogObserverBeatsLegacyComponentz=AppLoggerTests.test_configuredLogObserverBeatsLegacyComponent�sN��
��#�o��� � �!3�W�^�^�D����D�7�7��D�E�����"�%r6c�<�g}|j�}t�}|jt|�|jt|j
�t
ji�}|j|�|j|�|j|g�y)zw
        A L{ILogObserver} takes precedence over a L{LegacyILogObserver}
        component set on Application.
        N)r�rr�rr�r�r
r�r^r�rz)rQr�rhr]rs     r4�.test_loggerComponentBeatsLegacyLoggerComponentz=AppLoggerTests.test_loggerComponentBeatsLegacyLoggerComponent�s}��
���%�%�'��#�o��� � ��x�8�� � �!3�W�^�^�D����r�"������[�!����H�%�����"�%r6r�zsyslog not availablec��t|�}t�}|j|j|ddit��|j|g�y)z`
        C{--logger} takes precedence over a C{--syslog} command line
        argument.
        rvTN)rxrr�r�r"rz)rQ�logsr]s   r4�%test_configuredLogObserverBeatsSyslogz4AppLoggerTests.test_configuredLogObserverBeatsSyslog�sL���D�!��#�o������'�'��h��5E�}�U�	
�	
����r�"r6c���t�}|j�}|j|j|ddi��|j	t
jj|��y)za
        C{--logger} takes precedence over a C{--logfile} command line
        argument.
        �logfiler�N)rr�r�r�r�r:r�r�)rQr]r�s   r4�&test_configuredLogObserverBeatsLogfilez5AppLoggerTests.test_configuredLogObserverBeatsLogfile�sV��
$�o���{�{�}������'�'��i��5H�I�	
�	
���������-�.r6c���tjddi�}t|j�}|j�|jt
|�d�|j|dtj�tjddi�}|j�|jt
|�d�|j|dtj�y)z�
        When logfile is empty or set to C{-}, L{app.AppLogger._getLogObserver}
        returns a log observer pointing at C{sys.stdout}.
        r��-r�r�r�N)
r
r�rjrDr�rzrr�r0r�)rQrrfs   r4�test_getLogObserverStdoutz(AppLoggerTests.test_getLogObserverStdout�s���
���	�3�/�0��,�T�Z�Z�8������ �����X���*��
�
�h�q�k�3�:�:�.����	�2��/������ �����X���*��
�
�h�q�k�3�:�:�.r6c��t|j�}|j�}tjd|i�}|j�}|j
|jj�|jt|�d�|j|djtjj|��y)z�
        When passing the C{logfile} option, L{app.AppLogger._getLogObserver}
        returns a log observer pointing at the specified path.
        r�r�rN)rjrDr�r
r�r��
addCleanup�_outFiler
rzrr�r:�abspath)rQrf�filename�sutrhs     r4�test_getLogObserverFilez&AppLoggerTests.test_getLogObserverFiles���
-�T�Z�Z�8���;�;�=���m�m�Y��1�2���&�&�(������)�)�/�/�0�����X���*�����!��)�)�2�7�7�?�?�8�+D�Er6c�T��g�t�}�fd�}|jtd|�tji�}||_|j�|j�|g�|j�|j�|g�|j|j
�y)z�
        L{app.AppLogger.stop} removes the observer created in C{start}, and
        reinitialize its C{_observer} so that if C{stop} is called several
        times it doesn't break.
        c�(���j|�yr)r?)rh�removeds �r4�removez(AppLoggerTests.test_stop.<locals>.remove s����N�N�8�$r6r�N)	r1rDrr
r��	_observerr rzr�)rQrhr�rr�s    @r4�	test_stopzAppLoggerTests.test_stops�������8��	%�	
�
�
�%�'7��@����r�"��#�������
�����8�*�-�����
�����8�*�-����&�*�*�+r6c�f���g�tji�}tt�G�fd�d����fd�|_|j
t
��|jdt�d��|j|jg�}|jt|�d|�y)zt
        L{app.AppLogger} using a legacy logger observer still works, wrapping
        it in a compat shim.
        c���eZdZdZ�fd�Zy)�;AppLoggerTests.test_legacyObservers.<locals>.LoggerObserverzX
            An observer which implements the legacy L{LegacyILogObserver}.
            c�(���j|�y)z<
                Add C{x} to the logs list.
                Nr?)rQ�xr�s  �r4r�zDAppLoggerTests.test_legacyObservers.<locals>.LoggerObserver.__call__:s������A�r6N)rSrTrUrVr��r�s�r4�LoggerObserverr�4s
���
�
r6r�c�����Sr)rX)r�s�r4r�z5AppLoggerTests.test_legacyObservers.<locals>.<lambda>@s
���.�*:�r6r�rN)
r
r�rr��_observerFactoryr^rr�rr�test_legacyObserversrzr)rQr�warningsr�r�s   @@r4r�z#AppLoggerTests.test_legacyObservers,s����
�����r�"��	�'�	(�		�		�
)�		�#;�������]�_�%��
�
�m�%6�t�A�w�%?�@��%�%�t�'@�'@�&A�B������X���8�4r6c�X��g�tji�}�fd�|_|jt	��|jdt
�d��|j|jg�}|j|ddd�|jt|�d|�y)z�
        L{app.AppLogger} using a logger observer which does not implement
        L{ILogObserver} or L{LegacyILogObserver} will be wrapped in a compat
        shim and raise a L{DeprecationWarning}.
        c����jSr)r?r�s�r4r�zAAppLoggerTests.test_unmarkedObserversDeprecated.<locals>.<lambda>Os������r6r�rraZPassing a logger factory which makes log observers which do not implement twisted.logger.ILogObserver or twisted.python.log.ILogObserver to twisted.application.app.AppLogger was deprecated in Twisted 16.2. Please use a factory that produces twisted.logger.ILogObserver (or the legacy twisted.python.log.ILogObserver) implementing objects instead.r�N)r
r�r�r^rr�rr� test_unmarkedObserversDeprecatedrzr)rQrr�r�s   @r4r�z/AppLoggerTests.test_unmarkedObserversDeprecatedGs���������r�"��!4�������]�_�%��
�
�m�%6�t�A�w�%?�@��%�%�t�'L�'L�&M�N������Q�K�	�"�0�	
�	
����X���8�4r6N)rSrTrUrVrr�r�r�r�r�r
r�r�r�r�r�r�rr�rvr�r�r�r�r�r�r�rXr6r4rzrzBs����H�8��"H�	&�&�)+�c�m�m��0F�	-�	&�&�"���9�:���J�.�/�
#�0�;�
#�
/�/�&
F�,�*5�65r6rzc�T�eZdZdZd�Zd�Zd�Zd�Zd�Zd�Z	e
ed�d	��Zy
)�UnixAppLoggerTestszw
    Tests for L{UnixAppLogger}.

    @ivar signals: list of signal handlers installed.
    @type signals: C{list}
    c�L��g�_�fd�}�jtd|�y)zs
        Fake C{signal.signal} for not installing the handlers but saving them
        in C{self.signals}.
        c�@���jj||f�yr))�signalsr�)r�r�rQs  �r4�
fakeSignalz,UnixAppLoggerTests.setUp.<locals>.fakeSignalus����L�L����a��)r6�signalN)r�rDr�)rQr�s` r4rzUnixAppLoggerTests.setUpns#���
���	*�	
�
�
�6�8�Z�0r6c��t|j�}tddd��}|j�|j	t|�d�|j
|dtj�tddd��}|j�|j	t|�d�|j
|dtj�y)	z�
        When non-daemonized and C{logfile} is empty or set to C{-},
        L{UnixAppLogger._getLogObserver} returns a log observer pointing at
        C{sys.stdout}.
        r�T�r�rBr�rr�r�N)	rjrDr"r�rzrr�r0r�)rQrfrs   r4r�z,UnixAppLoggerTests.test_getLogObserverStdoutzs���-�T�Z�Z�8���3�D�A�B������ �����X���*��
�
�h�q�k�3�:�:�.��2�4�@�A������ �����X���*��
�
�h�q�k�3�:�:�.r6c��tddd��}|jt|j�}|j	t|�d�y)z
        When daemonized and C{logfile} is set to C{-},
        L{UnixAppLogger._getLogObserver} raises C{SystemExit}.
        r�Fr�z&Daemons cannot log to stdout, exiting!N)r"r�r�r�rzr�)rQrrXs   r4�test_getLogObserverStdoutDaemonz2UnixAppLoggerTests.test_getLogObserverStdoutDaemon�s@��
�3�E�B�C���!�!�*�f�.D�.D�E������U��%M�Nr6c���t|j�}|j�}td|i�}|j	�}|j|jj�|jt|�d�|j|djtjj|��|jt|j�d�|j|jddtj�t!���fd�}||d_|jdd}|dd��S)z�
        When C{logfile} contains a file name, L{app.AppLogger._getLogObserver}
        returns a log observer pointing at the specified path, and a signal
        handler rotating the log is installed.
        r�r�rc�(���jd�yr))�callback)�ds�r4�rotatez:UnixAppLoggerTests.test_getLogObserverFile.<locals>.rotate�s���
�J�J�t�r6N)rjrDr�r"r�r�r�r
rzrr�r:r�r�r��SIGUSR1rr�)rQrfr�r�rhr��	rotateLogr�s       @r4r�z*UnixAppLoggerTests.test_getLogObserverFile�s���-�T�Z�Z�8���;�;�=���Y��1�2���&�&�(������)�)�/�/�0�����X���*�����!��)�)�2�7�7�?�?�8�+D�E�����T�\�\�*�A�.�������a���+�V�^�^�<��J��	�$������L�L��O�A�&�	��$����r6c����fd�}�jtd|��j�}td|i�}|j	�}�j|jj��j�jg�y)zy
        If a signal handler is already installed,
        L{UnixAppLogger._getLogObserver} doesn't override it.
        c�X���j|tj�t�Sr))rzr�r�r1)r�rQs �r4�
fakeGetSignalzVUnixAppLoggerTests.test_getLogObserverDontOverrideSignalHandler.<locals>.fakeGetSignal�s������S�&�.�.�1��8�Or6�	getsignalr�N)
rDr�r�r"r�r�r�r
rzr�)rQr�r�r�rhs`    r4�,test_getLogObserverDontOverrideSignalHandlerz?UnixAppLoggerTests.test_getLogObserverDontOverrideSignalHandler�sn���	�	
�
�
�6�;�
�6��;�;�=���Y��1�2���&�&�(������)�)�/�/�0�������r�*r6c�d�t|j�}tddd��}|j�}|j	|j
j�|jt|�d�|j|djtjjd��y)z�
        When daemonized and C{logfile} is empty, the observer returned by
        L{UnixAppLogger._getLogObserver} points at C{twistd.log} in the current
        directory.
        r�Fr�r�rz
twistd.logN)rjrDr"r�r�r�r
rzrr�r:r�)rQrfrrhs    r4�test_getLogObserverDefaultFilez1UnixAppLoggerTests.test_getLogObserverDefaultFile�s���-�T�Z�Z�8���2�5�A�B��)�6�)�)�+������)�)�/�/�0�����X���*�����!��)�)�2�7�7�?�?�<�+H�Ir6r�c��t|�}tddd��}|j�}|j|dg�|ddi�|j|dddig�y)z�
        If C{syslog} is set to C{True}, L{UnixAppLogger._getLogObserver} starts
        a L{syslog.SyslogObserver} with given C{prefix}.
        Tztest-prefix)rvror��bN)rxr"r�rz)rQr�rrhs    r4�test_getLogObserverSyslogz,UnixAppLoggerTests.test_getLogObserverSyslog�sd���D�!���$�-�H�I��)�6�)�)�+������
��/��#�s�������
��S�z�:�;r6N)
rSrTrUrVrr�r�r�r�r�rr�r�rXr6r4r�r�esF���
1�/�$O��<+�&J����9�:�
<�;�
<r6r�z!twistd unix support not availablec�p�eZdZdZd�Zd�Zd�Zd�Zd�Zd�Z	d�Z
d	�Zd
�Zd�Z
d�Zd
�Zd�Zd�Zd�Zd�Zy)�DaemonizeTestszH
    Tests for L{_twistd_unix.UnixApplicationRunner} daemonization.
    c���t�|_tj�|_|jtd|j�tj|j�|_tjd�|j_tj|j_tj|j_d�|j_y)Nr:rc��yr)rX)r�s r4r�z&DaemonizeTests.setUp.<locals>.<lambda>�r�r6)r�mockosrr}r�rDr�r!rrrr]r0r�rJ�stderrrKrLrcs r4rzDaemonizeTests.setUp�s����h����*�*�,����
�
�<��t�{�{�3�"�8�8����E���")�"5�"5�e�"<����� #�
�
����� #�
�
�����#5���� r6c�(�tt��5|jj�ddd�|j	|j
jgd��|j	|j
jddg�y#1swY�ZxYw)zw
        When double fork succeeded in C{daemonize}, the child process writes
        B{0} to the status pipe.
        N)�r�r��r�r���forkT�setsidr�)r�����0��unlinkz
twistd.pid���r�)rr�rrfrzr��actions�closedrcs r4�test_successzDaemonizeTests.test_success�su��
�4�6�
7�	*��K�K�'�'�)�	*�����K�K���
�	
�	
������+�+�b�"�X�6�	*�	*�s�B�Bc��d|j_d|j_tt	��5|jt|jj�ddd�|j|jjgd��|j|jjdg�y#1swY�YxYw)z�
        The parent process initiating the C{daemonize} call reads data from the
        status pipe and then exit the process.
        Fr�N)r�r�r��r�����d��exitrr�r)r��child�readDatarr�r��SystemErrorrrfrzr�r�rcs r4�test_successInParentz#DaemonizeTests.test_successInParents���
"�����#�����
�4�6�
7�	H����k�4�;�;�+F�+F�G�	H�����K�K���
�
	
�	
������+�+�b�T�2�	H�	H�s�+B9�9Cc���g��fd�}||j_tt��5|jj�ddd�|j
|jjgd��|j
|jjddg�|j
ddg��y#1swY�nxYw)z�
        If the C{os.write} call to the status pipe raises an B{EINTR} error,
        the process child retries to write.
        c�z���j||f�t��dk(rttj��yr��r�rr�r��EINTR)�fdr,�writtens  �r4�raisingWritez6DaemonizeTests.test_successEINTR.<locals>.raisingWrite$s3����N�N�B��:�&��7�|�q� ��e�k�k�*�*�!r6N)r�r�r�r�r�r�r�r�)r�r�)	r�r�rr�rrfrzr�r�)rQrrs  @r4�test_successEINTRz DaemonizeTests.test_successEINTRs����
��	+�
)�����
�4�6�
7�	*��K�K�'�'�)�	*�����K�K���
�
	
�	
������+�+�b�"�X�6����*�j�1�7�;�	*�	*�s�B5�5B>c����g��fd�}||j_d|j_tt	��5|jt|jj�ddd�|j|jjgd��|j|jjdg�|jddg��y#1swY�mxYw)z
        If the C{os.read} call on the status pipe raises an B{EINTR} error, the
        parent child retries to read.
        c�z���j||f�t��dk(rttj��y)Nr�r�r)r
�sizer�s  �r4�raisingReadz=DaemonizeTests.test_successInParentEINTR.<locals>.raisingReadAs0����K�K��T�
�#��4�y�A�~��e�k�k�*�*�r6FN)r�r�r�rr�r)rr)r�r�rrr�r�rrrfrzr�r�)rQrr�s  @r4�test_successInParentEINTRz(DaemonizeTests.test_successInParentEINTR:s����
��	�'�����!�����
�4�6�
7�	H����k�4�;�;�+F�+F�G�	H�����K�K���
�		
�	
������+�+�b�T�2����)�Y�/��6�	H�	H�s�+C�Cc����G�fd�dtj�}|�}|j|jj�tt
��5|jt|jj�ddd�|j|jjddddddd	|fd
g�|j|jjdd	g�y#1swY�bxYw)z�
        Assert L{UnixApplicationRunner.postApplication} writes
        C{reported} to its status pipe if the service raises an
        exception whose message is C{raised}.
        c���eZdZ�fd�Zy)�6DaemonizeTests.assertErrorWritten.<locals>.FakeServicec���t���r)rK)rQ�raiseds �r4r_zCDaemonizeTests.assertErrorWritten.<locals>.FakeService.startService`s���"�6�*�*r6N)rSrTrUr_)rs�r4rdr_s���
+r6rdNr�r�r�r�r�r�r�r�)rrOrXrr]rr�r�r%rfrzr�r�r�)rQr�reportedrd�errorServices `   r4�assertErrorWrittenz!DaemonizeTests.assertErrorWrittenXs����	+�'�/�/�	+�#�}���%�%�d�k�k�&=�&=�>�
�4�6�
7�	I����l�D�K�K�,G�,G�H�	I�����K�K���� �����"�h�'�(�
�	
�	
������+�+�b�"�X�6�	I�	I�s�+C(�(C1c�*�|jdd��y)z�
        If an error happens during daemonization, the child process writes the
        exception error to the status pipe.
        zSomething is wrongs"1 RuntimeError: Something is wrong�rrN�rrcs r4�
test_errorzDaemonizeTests.test_errorvs��
	
���'�2W�	 �	
r6c�*�|jdd��y)z�
        If an error happens during daemonization, and that error's
        message is Unicode, the child encodes the message as ascii
        with backslash Unicode code points.
        u•s1 RuntimeError: \u2022rNr rcs r4�test_unicodeErrorz DaemonizeTests.test_unicodeErrors��	
���x�:T��Ur6c��d|j_||j_t�}|j	t
d|�t
t��5|jt|jj�ddd�|j|j�|�|j|jj|�|j|jjdg�y#1swY�wxYw)a
        Make L{os.read} appear to return C{readData}, and assert that
        L{UnixApplicationRunner.postApplication} writes
        C{errorMessage} to standard error and executes the calls
        against L{os} functions specified in C{mockOSActions}.
        F�
__stderr__Nr)r�rrrrDr0rr�r�rrrfrzr�r�r�)rQr�errorMessage�
mockOSActions�errorIOs     r4�assertErrorInParentBehaviorz*DaemonizeTests.assertErrorInParentBehavior�s���"�����'������*���
�
�3��g�.�
�4�6�
7�	H����k�4�;�;�+F�+F�G�	H�����)�)�+�\�:�������,�,�m�<�������+�+�b�T�2�		H�	H�s�+C8�8Dc�0�|jddgd���y)z�
        When the child writes an error message to the status pipe
        during daemonization, the parent writes the repr of the
        message to C{stderr} and exits with non-zero status code.
        s 1 Exception: An identified errorzgAn error has occurred: b'Exception: An identified error'
Please look at log file for more information.
�r�r�r�r)rr�r��rr&r'N�r)rcs r4�test_errorInParentz!DaemonizeTests.test_errorInParent�s%��	
�(�(�8�B��
	)�	
r6c�0�|jddgd���y)z�
        When the child writes a non-ASCII error message to the status
        pipe during daemonization, the parent writes the repr of the
        message to C{stderr} and exits with a non-zero status code.
        s1 Exception: �zXAn error has occurred: b'Exception: \xff'
Please look at log file for more information.
r+r,Nr-rcs r4�test_nonASCIIErrorInParentz)DaemonizeTests.test_nonASCIIErrorInParent�s%��	
�(�(�)�B��
	)�	
r6c�t�d}djd�}|j|dj|�gd���y)a

        When the child writes a non-ASCII error message to the status
        pipe during daemonization, and that message is too longer, the
        parent writes the repr of the truncated message to C{stderr}
        and exits with a non-zero status code.
        �d1 RuntimeError: \u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022zb'RuntimeError: {}'zb\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022\\u2022zHAn error has occurred: {}
Please look at log file for more information.
r+r,N)r�r))rQ�truncatedMessage�reportedMessages   r4�&test_errorInParentWithTruncatedUnicodez5DaemonizeTests.test_errorInParentWithTruncatedUnicode�sL��A��0�6�6��G���(�(�%�B�BH�&�#�C��	)�	
r6c�*�|jdd��y)z{
        If an error occurs during daemonization and its message is too
        long, it's truncated by the child.
        ��xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxsd1 RuntimeError: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxrNr rcs r4�test_errorMessageTruncatedz)DaemonizeTests.test_errorMessageTruncated�s��
	
����'F�	 �	
r6c�*�|jdd��y)z�
        If an error occurs during daemonization and its message is
        unicode and too long, it's truncated by the child, even if
        this splits a unicode escape sequence.
        uZ••••••••••••••••••••••••••••••r2rNr rcs r4�!test_unicodeErrorMessageTruncatedz0DaemonizeTests.test_unicodeErrorMessageTruncated�s��	
��� �:�	 �	
r6c��t�}|jj|�|j|j�|j|j
�y)z�
        C{daemonize} indeed calls L{IReactorDaemonize.beforeDaemonize} and
        L{IReactorDaemonize.afterDaemonize} if the reactor implements
        L{IReactorDaemonize}.
        N)r�rr�r�rrr�s  r4�test_hooksCalledzDaemonizeTests.test_hooksCalled�sB��)�*�������g�&�����6�6�7�����5�5�6r6c��t�}|jj|�|j|j�|j|j
�y)z�
        C{daemonize} does NOT call L{IReactorDaemonize.beforeDaemonize} or
        L{IReactorDaemonize.afterDaemonize} if the reactor does NOT implement
        L{IReactorDaemonize}.
        N)rrr�r�rrr�s  r4�test_hooksNotCalledz"DaemonizeTests.test_hooksNotCalledsF��,�-�������g�&�����7�7�8�����6�6�7r6N)rSrTrUrVrr�rrrrr!r#r)r.r0r5r8r:r<r>rXr6r4r�r��sX���6�7�*3�,<�:7�<7�<
�V�3�"
�,
�,
�:
�	
�	7�	8r6r�c�D�eZdZdZed��Zejd��Zy)�SignalCapturingMemoryReactorz�
    MemoryReactor that implements the _ISupportsExitSignalCapturing interface,
    all other operations identical to MemoryReactor.
    c��|jSr)��_valrcs r4r�z(SignalCapturingMemoryReactor._exitSignals���y�y�r6c��||_yr)rB)rQ�vals  r4r�z(SignalCapturingMemoryReactor._exitSignals	����	r6N)rSrTrUrV�propertyr��setterrXr6r4r@r@s5���
���������r6r@c�2��eZdZdZeZ�fd�Zd�Zd�Z�xZ	S)�StubApplicationRunnerWithSignalz�
    An application runner that uses a SignalCapturingMemoryReactor and
    has a _signalValue attribute that it will set in the reactor.

    @ivar _signalValue: The signal value to set on the reactor's _exitSignal
        attribute.
    c�2��t�|�|�d|_yr))�superrr�_signalValue)rQr��	__class__s  �r4rrz(StubApplicationRunnerWithSignal.__init__'s���
���� � ��r6c��y)z
        Does nothing.
        NrXrcs r4rdz.StubApplicationRunnerWithSignal.preApplication+r�r6c��t�}|j|_|j|tj
tj�y)z`
        Instantiate a SignalCapturingMemoryReactor and start it
        in the runner.
        N)r@rLr�rLr0r�r�r�s  r4rfz/StubApplicationRunnerWithSignal.postApplication0s4��
/�0��"�/�/������'�3�:�:�s�z�z�:r6)
rSrTrUrVrZrgrrrdrf�
__classcell__)rMs@r4rIrIs����&�M�!��
;r6rIc����fd�}|S)aI
    Create a factory function to instantiate a
    StubApplicationRunnerWithSignal that will report signum as the captured
    signal..

    @param signum: The integer signal number or None
    @type signum: C{int} or C{None}

    @return: A factory function to create stub runners.
    @rtype: stubApplicationRunnerFactory
    c�,��t|�}�|_|S)a�
        Create a StubApplicationRunnerWithSignal using a reactor that
        implements _ISupportsExitSignalCapturing and whose _exitSignal
        attribute is set to signum.

        @param config: The runner configuration, platform dependent.
        @type config: L{twisted.scripts.twistd.ServerOptions}

        @return: A runner to use for the test.
        @rtype: twisted.test.test_twistd.StubApplicationRunnerWithSignal
        )rIrL)r�r�signums  �r4�stubApplicationRunnerFactoryzIstubApplicationRunnerFactoryCreator.<locals>.stubApplicationRunnerFactoryGs���1��8��$����
r6rX)rSrTs` r4�#stubApplicationRunnerFactoryCreatorrU:s���� (�'r6c�(�eZdZdZd�Zd�Zd�Zd�Zy)�ExitWithSignalTestsz?
    Tests for L{twisted.application.app._exitWithSignal}.
    c���tj��_dt�i�j_t��j_d�j_ddg�_�fd�}�jtd|�y)zM
        Set up the server options and a fake for use by test cases.
        r.Nc�B��|�jd<|�jd<y)z�
            Fake method to capture arguments passed to os.kill.

            @param pid: The pid of the process being killed.

            @param sig: The signal sent to the process.
            rr�N)�fakeKillArgs)r�r�rQs  �r4�fakeKillz+ExitWithSignalTests.setUp.<locals>.fakeKilljs%���$'�D���a� �#&�D���a� r6r�)rr}r�rKr0r1r2r�rZrDr:)rQr[s` r4rzExitWithSignalTests.setUp`sg����*�*�,���%3�5E�5G�$H����!�!'������!/�����!�4�L���		'�	
�
�
�2�v�x�(r6c����ddg��fd�}|jtd|�tjtj�|j�dtj�|j�dtj�|j|jdtj��|j|jdtj�y)z�
        exitWithSignal replaces the existing signal handler with the default
        handler and sends the replaced signal to the current process.
        Nc���|�d<|�d<y)Nrr�rX)r��handler�fakeSignalArgss  �r4�fake_signalz<ExitWithSignalTests.test_exitWithSignal.<locals>.fake_signals��� #�N�1�� '�N�1�r6r�rr�)
rDr�r
�_exitWithSignal�SIGINTr��SIG_DFLrZr:r�)rQr`r_s  @r4�test_exitWithSignalz'ExitWithSignalTests.test_exitWithSignalws��������	(�	
�
�
�6�8�[�1����F�M�M�*����.��+�V�]�]�;����.��+�V�^�^�<����$�+�+�A�.��	�	��<����$�+�+�A�.��
�
�>r6c��|jtdtd��tj|j�|j|jd�|j|jd�y)zb
        _exitWithSignal is not called if the runner does not exit with a
        signal.
        reNrr�)rDrrU�runAppr�r�rZrcs r4�test_normalExitz#ExitWithSignalTests.test_normalExit�sc��
	
�
�
��,�.Q�RV�.W�	
�	�
�
�d�k�k�"����$�+�+�A�.�/����$�+�+�A�.�/r6c�Z�|jtdttj��tj
|j�|j|jdtj��|j|jdtj�y)zP
        _exitWithSignal is called when the runner exits with a signal.
        rerr�N)rDrrUr�rbrfr�r�rZr:r�rcs r4�test_runnerExitsWithSignalz.ExitWithSignalTests.test_runnerExitsWithSignal�st��	
�
�
��$�/��
�
�>�	
�
	�
�
�d�k�k�"����$�+�+�A�.��	�	��<����$�+�+�A�.��
�
�>r6N)rSrTrUrVrrdrgrirXr6r4rWrWZs���)�.?�(
0�?r6rW)hrVr�r�r:rr�r0r<�_grpr9�_pwd�ImportError�ior�unittestr�zope.interfacer�zope.interface.verifyrr�rrr	�twisted.applicationr
rr�twisted.application.servicer
�twisted.internet.baser�twisted.internet.deferr�twisted.internet.interfacesrr�#twisted.internet.test.modulehelpersr�twisted.internet.testingr�twisted.loggerrrr�twisted.pythonr�twisted.python.componentsr�twisted.python.fakepwdr�twisted.python.logr�r�twisted.python.reflectr�twisted.python.runtimer�twisted.python.usager�twisted.scriptsr�twisted.test.test_processr�twisted.trial.unittestr r��twisted.scripts._twistd_unixr!r"r#rvr$r%r&rIrKr�rZrerarir�r	rr$r"r,r�r�r	rr�rwr'rjrxrzr�r�r@rIrUrWrXr6r4�<module>r�s���

��	�
�
�
����
�C�
�C���&�.�,�,�6�6�5�-�+�X�@�2�N�N��3�/�T�0�/�+�"�,�+��;�<�����
�.�	/��
�	�
"��	�x�	 ����$��*.�Z��"
��
�
�
�

�� =� =�

� UJ��UJ�p�L��5�6�CK�H�CK�7�CK�LD�8�D�0��*J�C�1�1�J�(p4�X�p4�f�L��5�6�F+��F+�7�F+�R�L��5�6�O?��O?�7�O?�d�L��5�6�>�(�>�7�>�<��8
�
���6�� ����(w8��w8�t�*�$`5�X�`5�F	�L��5�6�y<��y<�7�y<�x�L��=�>�f8�X�f8�?�f8�R	
�
*�+��=��,��;�f�&C�&C�;�<(�@H?�(�H?��OB��
�C�
�C��s�I=�=	J
�	J

¿Qué es la limpieza dental de perros? - Clínica veterinaria


Es la eliminación del sarro y la placa adherida a la superficie de los dientes mediante un equipo de ultrasonidos que garantiza la integridad de las piezas dentales a la vez que elimina en profundidad cualquier resto de suciedad.

A continuación se procede al pulido de los dientes mediante una fresa especial que elimina la placa bacteriana y devuelve a los dientes el aspecto sano que deben tener.

Una vez terminado todo el proceso, se mantiene al perro en observación hasta que se despierta de la anestesia, bajo la atenta supervisión de un veterinario.

¿Cada cuánto tiempo tengo que hacerle una limpieza dental a mi perro?

A partir de cierta edad, los perros pueden necesitar una limpieza dental anual o bianual. Depende de cada caso. En líneas generales, puede decirse que los perros de razas pequeñas suelen acumular más sarro y suelen necesitar una atención mayor en cuanto a higiene dental.


Riesgos de una mala higiene


Los riesgos más evidentes de una mala higiene dental en los perros son los siguientes:

  • Cuando la acumulación de sarro no se trata, se puede producir una inflamación y retracción de las encías que puede descalzar el diente y provocar caídas.
  • Mal aliento (halitosis).
  • Sarro perros
  • Puede ir a más
  • Las bacterias de la placa pueden trasladarse a través del torrente circulatorio a órganos vitales como el corazón ocasionando problemas de endocarditis en las válvulas. Las bacterias pueden incluso acantonarse en huesos (La osteomielitis es la infección ósea, tanto cortical como medular) provocando mucho dolor y una artritis séptica).

¿Cómo se forma el sarro?

El sarro es la calcificación de la placa dental. Los restos de alimentos, junto con las bacterias presentes en la boca, van a formar la placa bacteriana o placa dental. Si la placa no se retira, al mezclarse con la saliva y los minerales presentes en ella, reaccionará formando una costra. La placa se calcifica y se forma el sarro.

El sarro, cuando se forma, es de color blanquecino pero a medida que pasa el tiempo se va poniendo amarillo y luego marrón.

Síntomas de una pobre higiene dental
La señal más obvia de una mala salud dental canina es el mal aliento.

Sin embargo, a veces no es tan fácil de detectar
Y hay perros que no se dejan abrir la boca por su dueño. Por ejemplo…

Recientemente nos trajeron a la clínica a un perro que parpadeaba de un ojo y decía su dueño que le picaba un lado de la cara. Tenía molestias y dificultad para comer, lo que había llevado a sus dueños a comprarle comida blanda (que suele ser un poco más cara y llevar más contenido en grasa) durante medio año. Después de una exploración oftalmológica, nos dimos cuenta de que el ojo tenía una úlcera en la córnea probablemente de rascarse . Además, el canto lateral del ojo estaba inflamado. Tenía lo que en humanos llamamos flemón pero como era un perro de pelo largo, no se le notaba a simple vista. Al abrirle la boca nos llamó la atención el ver una muela llena de sarro. Le realizamos una radiografía y encontramos una fístula que llegaba hasta la parte inferior del ojo.

Le tuvimos que extraer la muela. Tras esto, el ojo se curó completamente con unos colirios y una lentilla protectora de úlcera. Afortunadamente, la úlcera no profundizó y no perforó el ojo. Ahora el perro come perfectamente a pesar de haber perdido una muela.

¿Cómo mantener la higiene dental de tu perro?
Hay varias maneras de prevenir problemas derivados de la salud dental de tu perro.

Limpiezas de dientes en casa
Es recomendable limpiar los dientes de tu perro semanal o diariamente si se puede. Existe una gran variedad de productos que se pueden utilizar:

Pastas de dientes.
Cepillos de dientes o dedales para el dedo índice, que hacen más fácil la limpieza.
Colutorios para echar en agua de bebida o directamente sobre el diente en líquido o en spray.

En la Clínica Tus Veterinarios enseñamos a nuestros clientes a tomar el hábito de limpiar los dientes de sus perros desde que son cachorros. Esto responde a nuestro compromiso con la prevención de enfermedades caninas.

Hoy en día tenemos muchos clientes que limpian los dientes todos los días a su mascota, y como resultado, se ahorran el dinero de hacer limpiezas dentales profesionales y consiguen una mejor salud de su perro.


Limpiezas dentales profesionales de perros y gatos

Recomendamos hacer una limpieza dental especializada anualmente. La realizamos con un aparato de ultrasonidos que utiliza agua para quitar el sarro. Después, procedemos a pulir los dientes con un cepillo de alta velocidad y una pasta especial. Hacemos esto para proteger el esmalte.

La frecuencia de limpiezas dentales necesaria varía mucho entre razas. En general, las razas grandes tienen buena calidad de esmalte, por lo que no necesitan hacerlo tan a menudo e incluso pueden pasarse la vida sin requerir una limpieza. Sin embargo, razas pequeñas como el Yorkshire o el Maltés, deben hacérselas todos los años desde cachorros si se quiere conservar sus piezas dentales.

Otro factor fundamental es la calidad del pienso. Algunas marcas han diseñado croquetas que limpian la superficie del diente y de la muela al masticarse.

Ultrasonido para perros

¿Se necesita anestesia para las limpiezas dentales de perros y gatos?

La limpieza dental en perros no es una técnica que pueda practicarse sin anestesia general , aunque hay veces que los propietarios no quieren anestesiar y si tiene poco sarro y el perro es muy bueno se puede intentar…… , pero no se va a poder pulir ni acceder a todas la zona de la boca …. Además los limpiadores dentales van a irrigar agua y hay riesgo de aspiración a vías respiratorias si no se realiza una anestesia correcta con intubación traqueal . En resumen , sin anestesia no se va hacer una correcta limpieza dental.

Tampoco sirve la sedación ya que necesitamos que el animal esté totalmente quieto, y el veterinario tenga un acceso completo a todas sus piezas dentales y encías.

Alimentos para la limpieza dental

Hay que tener cierto cuidado a la hora de comprar determinados alimentos porque no todos son saludables. Algunos tienen demasiado contenido graso, que en exceso puede causar problemas cardiovasculares y obesidad.

Los mejores alimentos para los dientes son aquellos que están elaborados por empresas farmacéuticas y llevan componentes químicos con tratamientos específicos para el diente del perro. Esto implica no solo limpieza a través de la acción mecánica de morder sino también un tratamiento antibacteriano para prevenir el sarro.

Conclusión

Si eres como la mayoría de dueños, por falta de tiempo , es probable que no estés prestando la suficiente atención a la limpieza dental de tu perro. Por eso te animamos a que comiences a limpiar los dientes de tu perro y consideres atender a su higiene bucal con frecuencia.

Estas simples medidas pueden conllevar a que tu perro tenga una vida más larga y mucho más saludable.

Si te resulta imposible introducir un cepillo de dientes a tu perro en la boca, pásate con él por clínica Tus Veterinarios y te explicamos cómo hacerlo.

Necesitas hacer una limpieza dental profesional a tu mascota?
Llámanos al 622575274 o contacta con nosotros

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¡Hola!