Ë
    ¡–TiŒd  ã                   ó  — d 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 ddlmZmZmZmZ ddlmZ er	dd	lmZmZ n G d
„ d«      Z G d„ de«      Z G d„ de
«      Z G d„ de
«      Z G d„ de
«      Z ee d«       G d„ de«      «       Z ee d«       G d„ de«      «       Z ee d«       G d„ de«      «       Z ee d«       G d„ de«      «       Z ee d«       G d„ de«      «       Z ee d«       G d„ d e«      «       Zy!)"zv
Tests for django_cronjob_utils hooks integration.

Tests cover standard behavior, edge cases, and outlier scenarios.
é    )Údate)ÚskipIf)Úpatch)ÚTestCase)ÚCronTaskÚExecutionResult)ÚCronjobHookContextÚget_global_cronjob_hook_managerÚclear_cronjob_hooksÚHOOKS_AVAILABLE)ÚCronExecution)ÚHookTypeÚHookRejectionErrorc                   ó   — e Zd ZdZdZy)r   ÚpreÚpostN)Ú__name__Ú
__module__Ú__qualname__ÚPREÚPOST© ó    ú@/home/cursorai/projects/django-cronjob-utils/tests/test_hooks.pyr   r      s   „ ØˆØ‰r   r   c                   ó    ‡ — e Zd Zdˆ fd„	Zˆ xZS )r   c                 óV   •— || _         || _        |xs i | _        t        ‰| �  |«       y ©N)Ú
error_codeÚmessageÚdetailsÚsuperÚ__init__)Úselfr   r   r    Ú	__class__s       €r   r"   zHookRejectionError.__init__   s)   ø€ Ø(ˆDŒOØ"ˆDŒLØ"š= bˆDŒLÜ‰GÑ˜WÕ%r   r   )r   r   r   r"   Ú__classcell__©r$   s   @r   r   r      s   ø„ ÷	&ñ 	&r   r   c                   ó(   — e Zd ZdZdZdZdedefd„Zy)ÚTestTaskzTest task for hook tests.ú	test-taskÚT001r   Úreturnc                 ó   — dddœS )NFÚSuccess)Úerrorr   r   ©r#   r   s     r   ÚexecutezTestTask.execute+   s   € Ø¨9Ñ5Ð5r   N©	r   r   r   Ú__doc__Ú	task_nameÚ	task_coder   Údictr0   r   r   r   r(   r(   %   s"   „ Ù#à€IØ€Ið6˜Dð 6 Tô 6r   r(   c                   ó(   — e Zd ZdZdZdZdedefd„Zy)ÚFailingTaskzTask that always fails.zfailing-taskÚT002r   r+   c                 ó   — ddddœS )NTzTask failedÚFAIL)r.   r   r   r   r/   s     r   r0   zFailingTask.execute5   s   € Ø¨-ÀvÑNÐNr   Nr1   r   r   r   r7   r7   /   s%   „ Ù!à€IØ€IðO˜Dð O Tô Or   r7   c                   ó(   — e Zd ZdZdZdZdedefd„Zy)ÚExceptionTaskzTask that raises exception.zexception-taskÚT003r   r+   c                 ó   — t        d«      ‚)NzTest exception©Ú
ValueErrorr/   s     r   r0   zExceptionTask.execute?   s   € ÜÐ)Ó*Ð*r   Nr1   r   r   r   r<   r<   9   s"   „ Ù%à €IØ€Ið+˜Dð + Tô +r   r<   z"django-package-hooks not installedc                   ó@   ‡ — e Zd ZdZd„ Zˆ fd„Zd„ Zd„ Zd„ Zd„ Z	ˆ xZ
S )ÚHookContextCreationTestsz0Test CronjobHookContext creation and properties.c                 ó<   — t        ddd«      | _        t        «        y©zSet up test fixtures.iè  é   é   N)r   Úexecution_dater   ©r#   s    r   ÚsetUpzHookContextCreationTests.setUpK   s   € ä" 4¨¨BÓ/ˆÔÜÕr   c                 ó6   •— t        «        t        ‰| �	  «        y©zClean up after test.N©r   r!   ÚtearDown©r#   r$   s    €r   rM   z!HookContextCreationTests.tearDownP   ó   ø€ äÔÜ‰ÑÕr   c           
      ó´  — t        ddd| j                  dddiddi¬	«      }| j                  |j                  d«       | j                  |j                  d«       | j                  |j                  | j                  «       | j                  |j
                  d«       | j                  |j                  d   d«       | j                  |j                  d   d«       y
)z&Test creating context with all fields.r0   r)   r*   é{   ÚforceTÚcustomÚdata)Ú	operationr3   r4   rG   Úexecution_idÚoptionsÚmetadataN)r	   rG   ÚassertEqualr3   r4   rV   rW   rX   ©r#   Úcontexts     r   Ú%test_context_creation_with_all_fieldsz>HookContextCreationTests.test_context_creation_with_all_fieldsU   sÄ   € ä$ØØ!ØØ×.Ñ.ØØ˜d�OØ Ð'ô
ˆð 	×Ñ˜×*Ñ*¨KÔ8Ø×Ñ˜×*Ñ*¨FÔ3Ø×Ñ˜×/Ñ/°×1DÑ1DÔEØ×Ñ˜×-Ñ-¨sÔ3Ø×Ñ˜Ÿ™¨Ñ1°4Ô8Ø×Ñ˜×)Ñ)¨(Ñ3°VÕ<r   c                 ó˜  — t        ddd| j                  ¬«      }| j                  |j                  d«       | j                  |j                  d«       | j                  |j                  | j                  «       | j                  |j                  «       | j                  |j                  i «       | j                  |j                  i «       y)z3Test creating context with minimal required fields.r0   r)   r*   ©rU   r3   r4   rG   N)	r	   rG   rY   r3   r4   ÚassertIsNonerV   rW   rX   rZ   s     r   Útest_context_creation_minimalz6HookContextCreationTests.test_context_creation_minimalh   s¦   € ä$ØØ!ØØ×.Ñ.ô	
ˆð 	×Ñ˜×*Ñ*¨KÔ8Ø×Ñ˜×*Ñ*¨FÔ3Ø×Ñ˜×/Ñ/°×1DÑ1DÔEØ×Ñ˜'×.Ñ.Ô/Ø×Ñ˜Ÿ™¨"Ô-Ø×Ñ˜×)Ñ)¨2Õ.r   c                 ó˜   — t        ddd| j                  ¬«      }| j                  t        «      5  d|_        ddd«       y# 1 sw Y   yxY w)z2Test that context is immutable (frozen dataclass).r0   r)   r*   r^   ÚmodifiedN)r	   rG   ÚassertRaisesÚ	Exceptionr3   rZ   s     r   Útest_context_is_frozenz/HookContextCreationTests.test_context_is_frozenx   sB   € ä$ØØ!ØØ×.Ñ.ô	
ˆð ×ÑœyÕ)Ø *ˆGÔ÷ *×)Ñ)ús   ¯A Á A	c                 ó”   — t        ddd| j                  i ¬«      }d|j                  d<   | j                  |j                  d   d«       y)z:Test that metadata dict is mutable for hook communication.r0   r)   r*   )rU   r3   r4   rG   rX   Ú	new_valueÚnew_keyN)r	   rG   rX   rY   rZ   s     r   Ú test_context_metadata_is_mutablez9HookContextCreationTests.test_context_metadata_is_mutable„   sN   € ä$ØØ!ØØ×.Ñ.Øô
ˆð '2ˆ×Ñ˜Ñ#Ø×Ñ˜×)Ñ)¨)Ñ4°kÕBr   )r   r   r   r2   rI   rM   r\   r`   re   ri   r%   r&   s   @r   rB   rB   G   s%   ø„ á:òô
ò
=ò&/ò 
+öCr   rB   c                   óF   ‡ — e Zd ZdZd„ Zˆ fd„Zd„ Zd„ Zd„ Zd„ Z	d„ Z
ˆ xZS )	ÚPreHookStandardTestsz Test standard PRE hook behavior.c                 ó”   — t        ddd«      | _        t        «        t        j                  j                  «       j                  «        yrD   ©r   rG   r   r   ÚobjectsÚallÚdeleterH   s    r   rI   zPreHookStandardTests.setUp—   ó4   € ä" 4¨¨BÓ/ˆÔÜÔÜ×Ñ×!Ñ!Ó#×*Ñ*Õ,r   c                 ó6   •— t        «        t        ‰| �	  «        yrK   rL   rN   s    €r   rM   zPreHookStandardTests.tearDown�   rO   r   c                 ób  ‡ ‡— g Šˆˆ fd„}t        «       }|j                  j                  dt        j                  |d¬«       t        ‰ j                  ¬«      }|j                  «       }‰ j                  ‰«       ‰ j                  |j                  «       ‰ j                  |j                  d«       y)z$Test PRE hook that allows execution.c                 ó^   •— ‰j                  d«       ‰j                  | j                  «       y ©NT)Úappendr_   rV   )r[   Úhook_calledr#   s    €€r   Ú
allow_hookzGPreHookStandardTests.test_pre_hook_allows_execution.<locals>.allow_hook¦   s%   ø€ Ø×Ñ˜tÔ$Ø×Ñ˜g×2Ñ2Õ3r   rx   r0   ©rU   ©rG   r-   N)r
   ÚregistryÚregisterr   r   r(   rG   ÚrunÚ
assertTrueÚsuccessrY   r   )r#   rx   ÚmanagerÚtaskÚresultrw   s   `    @r   Útest_pre_hook_allows_executionz3PreHookStandardTests.test_pre_hook_allows_execution¢   s„   ù€ àˆõ	4ô
 2Ó3ˆØ×Ñ×!Ñ! ,´·±¸jÐT]Ð!Ô^ä t×':Ñ':Ô;ˆØ—‘“ˆà�‰˜Ô$Ø�‰˜Ÿ™Ô'Ø×Ñ˜Ÿ™¨Õ3r   c                 óÆ  — d„ }t        «       }|j                  j                  dt        j                  |d¬«       t        | j                  ¬«      }|j                  «       }| j                  |j                  «       | j                  |j                  d«       | j                  |j                  d«       | j                  t        j                  j                  «       d«       y	)
z%Test PRE hook that rejects execution.c                 ó   — t        dd¬«      ‚)NÚDEPENDENCY_NOT_METúRequired task not completed©r   r   ©r   ©r[   s    r   Úreject_hookzIPreHookStandardTests.test_pre_hook_rejects_execution.<locals>.reject_hook·   s   € Ü$Ø/Ø5ôð r   r‹   r0   ry   rz   r†   r‡   r   N)r
   r{   r|   r   r   r(   rG   r}   ÚassertFalser   rY   r   r   r   rn   Úcount©r#   r‹   r€   r�   r‚   s        r   Útest_pre_hook_rejects_executionz4PreHookStandardTests.test_pre_hook_rejects_executionµ   s­   € ò	ô 2Ó3ˆØ×Ñ×!Ñ! -´·±¸{ÐV_Ð!Ô`ä t×':Ñ':Ô;ˆØ—‘“ˆà×Ñ˜Ÿ™Ô(Ø×Ñ˜×*Ñ*Ð,@ÔAØ×Ñ˜Ÿ™Ð)FÔGð 	×Ñœ×.Ñ.×4Ñ4Ó6¸Õ:r   c                 óº  ‡— g Šˆfd„}t        «       }|j                  j                  dt        j                  |d¬«       t        | j                  dd¬«      }|j                  «        | j                  t        ‰«      d«       ‰d   }| j                  |j                  j                  d	«      «       | j                  |j                  j                  d
«      «       y)z$Test PRE hook receives task options.c                 ó(   •— ‰j                  | «       y r   ©rv   ©r[   Úcaptured_contexts    €r   Úcapture_hookzIPreHookStandardTests.test_pre_hook_receives_options.<locals>.capture_hookÎ   ó   ø€ Ø×#Ñ# GÕ,r   r•   r0   ry   T)rG   rR   ÚrerunrE   r   rR   r—   N)r
   r{   r|   r   r   r(   rG   r}   rY   Úlenr~   rW   Úget)r#   r•   r€   r�   r[   r”   s        @r   Útest_pre_hook_receives_optionsz3PreHookStandardTests.test_pre_hook_receives_optionsÊ   s­   ø€ àÐô	-ô 2Ó3ˆØ×Ñ×!Ñ! .´(·,±,ÀÐXaÐ!Ôbä t×':Ñ':À$ÈdÔSˆØ�‰Œ
à×ÑœÐ-Ó.°Ô2Ø" 1Ñ%ˆØ�‰˜Ÿ™×+Ñ+¨GÓ4Ô5Ø�‰˜Ÿ™×+Ñ+¨GÓ4Õ5r   c                 óÄ  ‡— g Šˆfd„}ˆfd„}ˆfd„}t        «       }|j                  j                  dt        j                  |dd¬«       |j                  j                  dt        j                  |dd	¬«       |j                  j                  d
t        j                  |dd¬«       t        | j                  ¬«      }|j                  «        | j                  ‰g d¢«       y)z2Test multiple PRE hooks execute in priority order.c                 ó(   •— ‰j                  d«       y )NÚhook_10r’   ©r[   Úexecution_orders    €r   Úhook_priority_10zUPreHookStandardTests.test_multiple_pre_hooks_priority_order.<locals>.hook_priority_10à   s   ø€ Ø×"Ñ" 9Õ-r   c                 ó(   •— ‰j                  d«       y )NÚhook_5r’   rž   s    €r   Úhook_priority_5zTPreHookStandardTests.test_multiple_pre_hooks_priority_order.<locals>.hook_priority_5ã   ó   ø€ Ø×"Ñ" 8Õ,r   c                 ó(   •— ‰j                  d«       y )NÚhook_1r’   rž   s    €r   Úhook_priority_1zTPreHookStandardTests.test_multiple_pre_hooks_priority_order.<locals>.hook_priority_1æ   r¤   r   r    r0   é
   ©rU   Úpriorityr£   é   r§   rE   rz   )r¦   r¢   r�   N)	r
   r{   r|   r   r   r(   rG   r}   rY   )r#   r    r£   r§   r€   r�   rŸ   s         @r   Ú&test_multiple_pre_hooks_priority_orderz;PreHookStandardTests.test_multiple_pre_hooks_priority_orderÜ   sÀ   ø€ àˆô	.ô	-ô	-ô 2Ó3ˆØ×Ñ×!Ñ!Ð"4´h·l±lÐDTÐ`iÐtvÐ!ÔwØ×Ñ×!Ñ!Ð"3´X·\±\À?Ð^gÐrsÐ!ÔtØ×Ñ×!Ñ!Ð"3´X·\±\À?Ð^gÐrsÐ!Ôtä t×':Ñ':Ô;ˆØ�‰Œ
ð 	×Ñ˜Ò*IÕJr   c                 ó’  ‡— g Šˆfd„}ˆfd„}t        «       }|j                  j                  dt        j                  |dd¬«       |j                  j                  dt        j                  |dd¬«       t        | j                  ¬	«      }|j                  «       }| j                  |j                  «       | j                  ‰d
g«       y)z5Test that first PRE hook rejection stops other hooks.c                 ó@   •— ‰j                  d«       t        dd¬«      ‚)NÚrejectÚREJECTEDÚRejectedrˆ   )rv   r   rž   s    €r   Úhook_rejectzWPreHookStandardTests.test_first_pre_hook_rejection_stops_execution.<locals>.hook_rejectø   s   ø€ Ø×"Ñ" 8Ô,Ü$°
ÀJÔOÐOr   c                 ó(   •— ‰j                  d«       y )NÚafterr’   rž   s    €r   Ú
hook_afterzVPreHookStandardTests.test_first_pre_hook_rejection_stops_execution.<locals>.hook_afterü   s   ø€ Ø×"Ñ" 7Õ+r   r²   r0   rE   r©   rµ   é   rz   r¯   N)r
   r{   r|   r   r   r(   rG   r}   rŒ   r   rY   )r#   r²   rµ   r€   r�   r‚   rŸ   s         @r   Ú-test_first_pre_hook_rejection_stops_executionzBPreHookStandardTests.test_first_pre_hook_rejection_stops_executionô   s¦   ø€ àˆô	Pô	,ô 2Ó3ˆØ×Ñ×!Ñ! -´·±¸{ÐV_ÐjkÐ!ÔlØ×Ñ×!Ñ! ,´·±¸jÐT]ÐhiÐ!Ôjä t×':Ñ':Ô;ˆØ—‘“ˆà×Ñ˜Ÿ™Ô(à×Ñ˜¨8¨*Õ5r   )r   r   r   r2   rI   rM   rƒ   r�   rš   r¬   r·   r%   r&   s   @r   rk   rk   “   s*   ø„ á*ò-ôò
4ò&;ò*6ò$Kö06r   rk   c                   ó4   — e Zd ZdZd„ Zd„ Zd„ Zd„ Zd„ Zd„ Z	y)	ÚPostHookStandardTestsz!Test standard POST hook behavior.c                 ó”   — t        ddd«      | _        t        «        t        j                  j                  «       j                  «        yrD   rm   rH   s    r   rI   zPostHookStandardTests.setUp  rq   r   c                 ó²  ‡— g Šˆfd„}t        «       }|j                  j                  dt        j                  |d¬«       t        | j                  ¬«      }|j                  «       }| j                  |j                  «       | j                  t        ‰«      d«       ‰d   }| j                  |j                  «       | j                  |j                  d«       y	)
z4Test POST hook receives successful execution result.c                 ó(   •— ‰j                  | «       y r   r’   r“   s    €r   Ú	post_hookzOPostHookStandardTests.test_post_hook_receives_success_result.<locals>.post_hook  r–   r   r½   r0   ry   rz   rE   r   r)   N)r
   r{   r|   r   r   r(   rG   r}   r~   r   rY   r˜   ÚassertIsNotNonerV   r3   ©r#   r½   r€   r�   r‚   r[   r”   s         @r   Ú&test_post_hook_receives_success_resultz<PostHookStandardTests.test_post_hook_receives_success_result  s¯   ø€ àÐô	-ô 2Ó3ˆØ×Ñ×!Ñ! +¬x¯}©}¸iÐS\Ð!Ô]ä t×':Ñ':Ô;ˆØ—‘“ˆà�‰˜Ÿ™Ô'Ø×ÑœÐ-Ó.°Ô2à" 1Ñ%ˆØ×Ñ˜W×1Ñ1Ô2Ø×Ñ˜×*Ñ*¨KÕ8r   c                 óz  ‡— g Šˆfd„}t        «       }|j                  j                  dt        j                  |d¬«       t        | j                  ¬«      }|j                  «       }| j                  |j                  «       | j                  t        ‰«      d«       ‰d   }| j                  |j                  «       y)	z0Test POST hook receives failed execution result.c                 ó(   •— ‰j                  | «       y r   r’   r“   s    €r   r½   zOPostHookStandardTests.test_post_hook_receives_failure_result.<locals>.post_hook-  r–   r   r½   r0   ry   rz   rE   r   N)r
   r{   r|   r   r   r7   rG   r}   rŒ   r   rY   r˜   r¾   rV   r¿   s         @r   Ú&test_post_hook_receives_failure_resultz<PostHookStandardTests.test_post_hook_receives_failure_result)  s›   ø€ àÐô	-ô 2Ó3ˆØ×Ñ×!Ñ! +¬x¯}©}¸iÐS\Ð!Ô]ä¨$×*=Ñ*=Ô>ˆØ—‘“ˆà×Ñ˜Ÿ™Ô(Ø×ÑœÐ-Ó.°Ô2à" 1Ñ%ˆØ×Ñ˜W×1Ñ1Õ2r   c                 ó2  — d„ }t        «       }|j                  j                  dt        j                  |d¬«       t        | j                  ¬«      }|j                  «       }| j                  |j                  «       | j                  |j                  d«       y)z8Test POST hook rejections don't affect execution result.c                 ó   — t        dd¬«      ‚)NÚPOST_REJECTzShould be ignoredrˆ   r‰   rŠ   s    r   Úpost_hook_rejectzLPostHookStandardTests.test_post_hook_cannot_reject.<locals>.post_hook_reject>  s   € ô %°ÐGZÔ[Ð[r   rÇ   r0   ry   rz   r-   N)r
   r{   r|   r   r   r(   rG   r}   r~   r   rY   r   )r#   rÇ   r€   r�   r‚   s        r   Útest_post_hook_cannot_rejectz2PostHookStandardTests.test_post_hook_cannot_reject<  sw   € ò	\ô
 2Ó3ˆØ×Ñ×!Ñ!Ð"4´h·m±mÐEUÐajÐ!Ôkä t×':Ñ':Ô;ˆØ—‘“ˆð 	�‰˜Ÿ™Ô'Ø×Ñ˜Ÿ™¨Õ3r   c                 ó^  ‡— g Šˆfd„}ˆfd„}t        «       }|j                  j                  dt        j                  |dd¬«       |j                  j                  dt        j                  |dd¬«       t        | j                  ¬	«      }|j                  «        | j                  ‰d
dg«       y)z%Test multiple POST hooks all execute.c                 ó(   •— ‰j                  d«       y )NÚar’   rž   s    €r   Úhook_azJPostHookStandardTests.test_multiple_post_hooks_all_execute.<locals>.hook_aQ  ó   ø€ Ø×"Ñ" 3Õ'r   c                 ó(   •— ‰j                  d«       y )NÚbr’   rž   s    €r   Úhook_bzJPostHookStandardTests.test_multiple_post_hooks_all_execute.<locals>.hook_bT  rÍ   r   rÌ   r0   rE   r©   rÐ   r¶   rz   rË   rÏ   N)	r
   r{   r|   r   r   r(   rG   r}   rY   )r#   rÌ   rÐ   r€   r�   rŸ   s        @r   Ú$test_multiple_post_hooks_all_executez:PostHookStandardTests.test_multiple_post_hooks_all_executeM  s‘   ø€ àˆô	(ô	(ô 2Ó3ˆØ×Ñ×!Ñ! (¬H¯M©M¸6ÈYÐabÐ!ÔcØ×Ñ×!Ñ! (¬H¯M©M¸6ÈYÐabÐ!Ôcä t×':Ñ':Ô;ˆØ�‰Œ
à×Ñ˜¨3°¨*Õ5r   c                 ón  — d„ }t        «       }|j                  j                  dt        j                  |d¬«       t        | j                  ¬«      }t        d«      5 }|j                  «       }| j                  |j                  «       |j                  j                  «        ddd«       y# 1 sw Y   yxY w)z=Test POST hook exceptions are logged but don't affect result.c                 ó   — t        d«      ‚)NzPOST hook errorr?   rŠ   s    r   Úpost_hook_exceptionzaPostHookStandardTests.test_post_hook_exception_logged_but_not_raised.<locals>.post_hook_exceptionb  s   € ÜÐ.Ó/Ð/r   rÔ   r0   ry   rz   z django_cronjob_utils.base.loggerN)r
   r{   r|   r   r   r(   rG   r   r}   r~   r   ÚwarningÚassert_called)r#   rÔ   r€   r�   Úmock_loggerr‚   s         r   Ú.test_post_hook_exception_logged_but_not_raisedzDPostHookStandardTests.test_post_hook_exception_logged_but_not_raised`  s�   € ò	0ô 2Ó3ˆØ×Ñ×!Ñ!Ð"7¼¿¹ÐH[ÐgpÐ!Ôqä t×':Ñ':Ô;ˆô Ð5Ô6¸+Ø—X‘X“ZˆFð �O‰O˜FŸN™NÔ+ð ×Ñ×-Ñ-Ô/÷ 7×6Ñ6ús   ÁAB+Â+B4N)
r   r   r   r2   rI   rÀ   rÃ   rÈ   rÑ   rØ   r   r   r   r¹   r¹     s#   „ á+ò-ò9ò(3ò&4ò"6ó&0r   r¹   c                   ó4   — e Zd ZdZd„ Zd„ Zd„ Zd„ Zd„ Zd„ Z	y)	ÚHookEdgeCaseTestsz!Test edge cases in hook behavior.c                 ó”   — t        ddd«      | _        t        «        t        j                  j                  «       j                  «        yrD   rm   rH   s    r   rI   zHookEdgeCaseTests.setUp}  rq   r   c                 ó”  ‡— d„ }g Šˆfd„}t        «       }|j                  j                  dt        j                  |d¬«       |j                  j                  dt        j
                  |d¬«       t        | j                  ¬«      }|j                  «        | j                  t        ‰«      d«       | j                  ‰d	   d
   d«       y)z1Test PRE hook can modify metadata for POST hooks.c                 ó"   — d| j                   d<   y )NÚfrom_preÚpre_hook_data)rX   rŠ   s    r   Úpre_hookzCHookEdgeCaseTests.test_pre_hook_modifies_metadata.<locals>.pre_hook…  s   € Ø0:ˆG×Ñ˜_Ò-r   c                 óX   •— ‰j                  | j                  j                  «       «       y r   )rv   rX   Úcopy)r[   Úcaptured_metadatas    €r   r½   zDHookEdgeCaseTests.test_pre_hook_modifies_metadata.<locals>.post_hookŠ  s    ø€ Ø×$Ñ$ W×%5Ñ%5×%:Ñ%:Ó%<Õ=r   rà   r0   ry   r½   rz   rE   r   rß   rÞ   N)r
   r{   r|   r   r   r   r(   rG   r}   rY   r˜   )r#   rà   r½   r€   r�   rã   s        @r   Útest_pre_hook_modifies_metadataz1HookEdgeCaseTests.test_pre_hook_modifies_metadataƒ  s¯   ø€ ò	;ð Ðô	>ô 2Ó3ˆØ×Ñ×!Ñ! *¬h¯l©l¸HÐPYÐ!ÔZØ×Ñ×!Ñ! +¬x¯}©}¸iÐS\Ð!Ô]ä t×':Ñ':Ô;ˆØ�‰Œ
ð 	×ÑœÐ.Ó/°Ô3Ø×ÑÐ*¨1Ñ-¨oÑ>À
ÕKr   c                 óZ  ‡—  G d„ dt         «      }g Šˆfd„}t        «       }|j                  j                  dt        j
                  |d¬«        || j                  ¬«      }|j                  «       }| j                  |j                  «       | j                  ‰d   j                  d	«       y
)z(Test hook with task that has empty code.c                   ó$   — e Zd ZdZdZdedefd„Zy)úDHookEdgeCaseTests.test_hook_with_empty_task_code.<locals>.NoCodeTaskzno-code-taskÚ r   r+   c                 ó
   — ddiS )Nr.   Fr   r/   s     r   r0   zLHookEdgeCaseTests.test_hook_with_empty_task_code.<locals>.NoCodeTask.executež  s   € Ø Ð'Ð'r   N)r   r   r   r3   r4   r   r5   r0   r   r   r   Ú
NoCodeTaskrç   š  s   „ Ø&ˆIØˆIð( Dð (¨Tô (r   rê   c                 ó(   •— ‰j                  | «       y r   r’   r“   s    €r   rà   zBHookEdgeCaseTests.test_hook_with_empty_task_code.<locals>.pre_hook£  r–   r   rà   r0   ry   rz   r   rè   N)r   r
   r{   r|   r   r   rG   r}   r~   r   rY   r4   )r#   rê   rà   r€   r�   r‚   r”   s         @r   Útest_hook_with_empty_task_codez0HookEdgeCaseTests.test_hook_with_empty_task_code˜  s�   ø€ ô	(œô 	(ð Ðô	-ô 2Ó3ˆØ×Ñ×!Ñ! *¬h¯l©l¸HÐPYÐ!ÔZá¨×)<Ñ)<Ô=ˆØ—‘“ˆà�‰˜Ÿ™Ô'Ø×ÑÐ)¨!Ñ,×6Ñ6¸Õ;r   c                 ó2  — d„ }t        «       }|j                  j                  dt        j                  |d¬«       t        | j                  ¬«      }|j                  «       }| j                  |j                  «       | j                  |j                  d«       y)z0Test PRE hook rejection with minimal error info.c                 ó   — t        dd¬«      ‚)NÚMINIMALrè   rˆ   r‰   rŠ   s    r   r‹   zPHookEdgeCaseTests.test_pre_hook_rejection_with_minimal_info.<locals>.reject_hook±  s   € ä$°	À2ÔFÐFr   r‹   r0   ry   rz   rï   N)r
   r{   r|   r   r   r(   rG   r}   rŒ   r   rY   r   rŽ   s        r   Ú)test_pre_hook_rejection_with_minimal_infoz;HookEdgeCaseTests.test_pre_hook_rejection_with_minimal_info¯  sw   € ò	Gô 2Ó3ˆØ×Ñ×!Ñ! -´·±¸{ÐV_Ð!Ô`ä t×':Ñ':Ô;ˆØ—‘“ˆà×Ñ˜Ÿ™Ô(Ø×Ñ˜×*Ñ*¨IÕ6r   c                 ó¦  — d„ }t        «       }|j                  j                  dt        j                  |d¬«       t        | j                  ¬«      }|j                  «       }| j                  |j                  «       | j                  |j                  d«       | j                  |j                  «       | j                  |j                  d   d«       y	)
z+Test PRE hook rejection with extra details.c                 ó$   — t        dddddœ¬«      ‚)NÚWITH_DETAILSzRejected with detailsÚ
dependencyz
other-task)ÚreasonÚrequired_task)r   r   r    r‰   rŠ   s    r   r‹   zQHookEdgeCaseTests.test_pre_hook_rejection_with_extra_details.<locals>.reject_hookÀ  s   € Ü$Ø)Ø/Ø#/À,ÑOôð r   r‹   r0   ry   rz   ró   rõ   rô   N)r
   r{   r|   r   r   r(   rG   r}   rŒ   r   rY   r   r¾   rT   rŽ   s        r   Ú*test_pre_hook_rejection_with_extra_detailsz<HookEdgeCaseTests.test_pre_hook_rejection_with_extra_details¾  s¡   € ò	ô 2Ó3ˆØ×Ñ×!Ñ! -´·±¸{ÐV_Ð!Ô`ä t×':Ñ':Ô;ˆØ—‘“ˆà×Ñ˜Ÿ™Ô(Ø×Ñ˜×*Ñ*¨NÔ;Ø×Ñ˜VŸ[™[Ô)Ø×Ñ˜Ÿ™ XÑ.°Õ=r   c                 ó"  ‡— g Šˆfd„}t        «       }|j                  j                  dt        j                  |d¬«       t        | j                  ¬«      }| j                  t        «      5  |j                  «        ddd«       y# 1 sw Y   yxY w)z4Test POST hooks behavior when task raises exception.c                 ó(   •— ‰j                  | «       y r   r’   r“   s    €r   r½   zTHookEdgeCaseTests.test_task_with_exception_still_calls_post_hooks.<locals>.post_hookÖ  r–   r   Úpost_hook_exceptr0   ry   rz   N)
r
   r{   r|   r   r   r<   rG   rc   r@   r}   )r#   r½   r€   r�   r”   s       @r   Ú/test_task_with_exception_still_calls_post_hookszAHookEdgeCaseTests.test_task_with_exception_still_calls_post_hooksÒ  sp   ø€ àÐô	-ô 2Ó3ˆØ×Ñ×!Ñ!Ð"4´h·m±mÀYÐZcÐ!Ôdä¨D×,?Ñ,?Ô@ˆð ×ÑœzÕ*Ø�H‰HŒJ÷ +×*Ñ*ús   Á+BÂBN)
r   r   r   r2   rI   rä   rì   rð   r÷   rû   r   r   r   rÚ   rÚ   y  s$   „ á+ò-òLò*<ò.7ò>ó(r   rÚ   c                   ó(   — e Zd ZdZd„ Zd„ Zd„ Zd„ Zy)ÚHookOutlierTestsz!Test outlier scenarios for hooks.c                 ó”   — t        ddd«      | _        t        «        t        j                  j                  «       j                  «        yrD   rm   rH   s    r   rI   zHookOutlierTests.setUpð  rq   r   c                 ó„   ‡— g Šˆfd„}t        | j                  ¬«      }|j                  «        | j                  ‰g «       y)z:Test hook registered for different event is not triggered.c                 ó(   •— ‰j                  d«       y ru   r’   )r[   rw   s    €r   ÚhookzGHookOutlierTests.test_hook_registered_but_never_triggered.<locals>.hookú  s   ø€ Ø×Ñ˜tÕ$r   rz   N)r(   rG   r}   rY   )r#   r  r�   rw   s      @r   Ú(test_hook_registered_but_never_triggeredz9HookOutlierTests.test_hook_registered_but_never_triggeredö  s:   ø€ àˆô	%ô  t×':Ñ':Ô;ˆØ�‰Œ
ð 	×Ñ˜ bÕ)r   c                 ó¶  ‡— g Št        «       }t        d«      D ]>  }ˆfd„}|j                  j                  d|› �t        j
                   ||«      d|¬«       Œ@ t        | j                  ¬«      }|j                  «       }| j                  |j                  «       | j                  t        ‰«      d«       | j                  ‰t        t        d«      «      «       y)z'Test system with many hooks registered.é   c                 ó   •‡ — ˆˆ fd„}|S )Nc                 ó(   •— ‰j                  ‰«       y r   r’   )r[   rŸ   Úindexs    €€r   r  zMHookOutlierTests.test_many_hooks_performance.<locals>.make_hook.<locals>.hook  s   ø€ Ø#×*Ñ*¨5Õ1r   r   )r  r  rŸ   s   ` €r   Ú	make_hookz?HookOutlierTests.test_many_hooks_performance.<locals>.make_hook  s   ù€ õ2à�r   Úhook_r0   r©   rz   N)r
   Úranger{   r|   r   r   r(   rG   r}   r~   r   rY   r˜   Úlist)r#   r€   Úir  r�   r‚   rŸ   s         @r   Útest_many_hooks_performancez,HookOutlierTests.test_many_hooks_performance  s²   ø€ àˆô 2Ó3ˆÜ�r–ˆAôð
 ×Ñ×%Ñ%¨¨a¨S k´8·<±<ÁÈ1ÃÐYbÐmnÐ%Õoð ô  t×':Ñ':Ô;ˆØ—‘“ˆð 	�‰˜Ÿ™Ô'Ø×Ñœ˜_Ó-¨rÔ2Ø×Ñ˜¬$¬u°R«y«/Õ:r   c                 ó–  — t         j                  j                  «       }d„ }t        «       }|j                  j                  dt        j                  |d¬«       t        | j                  ¬«      }|j                  «       }| j                  |j                  «       t         j                  j                  «       }| j                  ||«       y)z8Test PRE hook rejection doesn't create orphaned records.c                 ó   — t        dd¬«      ‚)Nr°   z
No recordsrˆ   r‰   rŠ   s    r   r‹   zVHookOutlierTests.test_pre_hook_rejection_preserves_database_state.<locals>.reject_hook!  s   € Ü$°
ÀLÔQÐQr   r‹   r0   ry   rz   N)r   rn   r�   r
   r{   r|   r   r   r(   rG   r}   rŒ   r   rY   )r#   Úinitial_countr‹   r€   r�   r‚   Úfinal_counts          r   Ú0test_pre_hook_rejection_preserves_database_statezAHookOutlierTests.test_pre_hook_rejection_preserves_database_state  s›   € ô &×-Ñ-×3Ñ3Ó5ˆò	Rô 2Ó3ˆØ×Ñ×!Ñ! -´·±¸{ÐV_Ð!Ô`ä t×':Ñ':Ô;ˆØ—‘“ˆà×Ñ˜Ÿ™Ô(ä#×+Ñ+×1Ñ1Ó3ˆØ×Ñ˜¨Õ4r   N)r   r   r   r2   rI   r  r  r  r   r   r   rý   rý   ì  s   „ á+ò-ò*ò ;ó,5r   rý   c                   ó:   ‡ — e Zd ZdZd„ Zˆ fd„Zd„ Zd„ Zd„ Zˆ xZ	S )ÚHookIntegrationTestsz+Test real-world hook integration scenarios.c                 ó”   — t        ddd«      | _        t        «        t        j                  j                  «       j                  «        yrD   rm   rH   s    r   rI   zHookIntegrationTests.setUp8  rq   r   c                 ó6   •— t        «        t        ‰| �	  «        yrK   rL   rN   s    €r   rM   zHookIntegrationTests.tearDown>  rO   r   c                 ó˜  — t        | j                  ¬«      }d|_        d|_        |j	                  «       }| j                  |j                  «       d„ }t        «       }|j                  j                  dt        j                  |d¬«       t        | j                  ¬«      }|j	                  «       }| j                  |j                  «       y)	z(Test realistic dependency checking hook.rz   zdependency-taskÚDEP001c                 ó¸   — | j                   dk(  rKt        j                  j                  d| j                  dd¬«      j                  «       }|st        dd¬«      ‚y y )Nr*   r  T)r4   rG   Ú	completedr   r†   z"Required task DEP001 not completedrˆ   )r4   r   rn   ÚfilterrG   Úexistsr   )r[   Údependency_existss     r   Úcheck_dependencyzLHookIntegrationTests.test_dependency_checking_hook.<locals>.check_dependencyL  sl   € Ø× Ñ  FÒ*ä$1×$9Ñ$9×$@Ñ$@Ø&Ø#*×#9Ñ#9Ø"Ø ð	 %Aó %÷
 ‘&“(ð "ñ )Ü,Ø#7Ø Dôð ð )ð +r   r  r0   ry   N)r(   rG   r3   r4   r}   r~   r   r
   r{   r|   r   r   )r#   Údependency_taskÚdependency_resultr  r€   r�   r‚   s          r   Útest_dependency_checking_hookz2HookIntegrationTests.test_dependency_checking_hookC  s¨   € ô #°$×2EÑ2EÔFˆØ$5ˆÔ!Ø$,ˆÔ!Ø+×/Ñ/Ó1ÐØ�‰Ð)×1Ñ1Ô2ò	ô  2Ó3ˆØ×Ñ×!Ñ!Ð"4´h·l±lÐDTÐ`iÐ!Ôjô  t×':Ñ':Ô;ˆØ—‘“ˆð 	�‰˜Ÿ™Õ'r   c                 ó¬  ‡— g Šˆfd„}t        «       }|j                  j                  dt        j                  |d¬«       t        | j                  ¬«      }|j                  «        t        | j                  ¬«      }|j                  «        | j                  t        ‰«      d«       | j                  ‰d   d   «       | j                  ‰d	   d   «       y
)z'Test realistic audit logging POST hook.c                 óð   •— | j                   rit        j                  j                  | j                   ¬«      }‰j	                  | j
                  |j                  |j                  |j                  dœ«       y y )N)Úid)r�   r  r   Úduration)	rV   r   rn   r™   rv   r3   r  r   r%  )r[   Ú	executionÚ	audit_logs     €r   Ú
audit_hookz@HookIntegrationTests.test_audit_logging_hook.<locals>.audit_hookj  sg   ø€ à×#Ò#Ü)×1Ñ1×5Ñ5¸×9MÑ9MÐ5ÓN�	Ø× Ñ Ø#×-Ñ-Ø!*×!4Ñ!4Ø(×0Ñ0Ø )× 2Ñ 2ñ	"õ ð $r   r(  r0   ry   rz   r¶   r   r   rE   N)r
   r{   r|   r   r   r(   rG   r}   r7   rY   r˜   r~   rŒ   )r#   r(  r€   Útask1Útask2r'  s        @r   Útest_audit_logging_hookz,HookIntegrationTests.test_audit_logging_hookf  s±   ø€ àˆ	ô		ô 2Ó3ˆØ×Ñ×!Ñ! ,´·±¸zÐU^Ð!Ô_ô ¨×(;Ñ(;Ô<ˆØ�	‰	Œô ¨4×+>Ñ+>Ô?ˆØ�	‰	Œð 	×Ñœ˜Y›¨Ô+Ø�‰˜	 !™ YÑ/Ô0Ø×Ñ˜ 1™ iÑ0Õ1r   c                 ó0  — d„ }t        «       }|j                  j                  dt        j                  |d¬«       t        d«      D ]p  }t        | j                  d¬«      }|j                  «       }| j                  |j                  «       |j                  dk7  sŒU| j                  |j                  d	«       Œr t        | j                  d¬«      }|j                  «       }| j                  |j                  «       | j                  |j                  d«       y
)z%Test hook that limits retry attempts.c                 óÖ   — | j                   dk(  rZt        j                  j                  | j                   | j                  ¬«      j                  «       }|dk\  rt        dd|› d�¬«      ‚y y )Nr8   )r4   rG   é   ÚMAX_RETRIES_EXCEEDEDzTask has already failed z timesrˆ   )r4   r   rn   r  rG   r�   r   )r[   Úretry_counts     r   Úlimit_retrieszDHookIntegrationTests.test_retry_limiting_hook.<locals>.limit_retries‡  sy   € Ø× Ñ  FÒ*ä+×3Ñ3×:Ñ:Ø%×/Ñ/Ø#*×#9Ñ#9ð ;ó ÷ ‘%“'ð ð
  !Ò#Ü,Ø#9Ø":¸;¸-ÀvÐ Nôð ð $ð +r   r1  r0   ry   r.  T)rG   rR   r/  r:   N)r
   r{   r|   r   r   r
  r7   rG   r}   rŒ   r   r   rY   )r#   r1  r€   r  r�   r‚   s         r   Útest_retry_limiting_hookz-HookIntegrationTests.test_retry_limiting_hook…  sß   € ò	ô 2Ó3ˆØ×Ñ×!Ñ! /´8·<±<ÀÐZcÐ!Ôdô �q–ˆAÜ¨d×.AÑ.AÈÔNˆDØ—X‘X“ZˆFØ×Ñ˜VŸ^™^Ô,Ø× Ñ Ð$:Ó:Ø× Ñ  ×!2Ñ!2°FÕ;ð ô ¨$×*=Ñ*=ÀTÔJˆØ—‘“ˆØ×Ñ˜Ÿ™Ô(Ø×Ñ˜×*Ñ*Ð,BÕCr   )
r   r   r   r2   rI   rM   r!  r+  r2  r%   r&   s   @r   r  r  4  s!   ø„ á5ò-ôò
!(òF2ö> Dr   r  N) r2   Údatetimer   Úunittestr   Úunittest.mockr   Údjango.testr   Údjango_cronjob_utils.baser   r   Údjango_cronjob_utils.hooksr	   r
   r   r   Údjango_cronjob_utils.modelsr   Údjango_package_hooksr   r   rd   r(   r7   r<   rB   rk   r¹   rÚ   rý   r  r   r   r   Ú<module>r;     sx  ðñõ
 Ý Ý Ý  ç ?÷ó õ 6ñ ßAÐA÷ñ ô&˜Yô &ô6ˆxô 6ôO�(ô Oô+�Hô +ñ ˆOÐÐAÓBôHC˜xó HCó CðHCñV ˆOÐÐAÓBôt6˜8ó t6ó Cðt6ñn ˆOÐÐAÓBôf0˜Hó f0ó Cðf0ñZ ˆOÐÐAÓBôf˜ó fó Cðfñd ˆOÐÐAÓBô@5�xó @5ó Cð@5ñN ˆOÐÐAÓBôpD˜8ó pDó CñpDr   