
    Vh5                        d dl mZ dZd dlZd dlZd dlZd dlmZ d dl	m
Z
mZ d dlmZ d dlmZmZmZmZmZ  G d d	e      Z G d
 d      Z G d d      Zy)    )annotationsa  
    name: junit
    type: aggregate
    short_description: write playbook output to a JUnit file.
    version_added: historical
    description:
      - This callback writes playbook output to a JUnit formatted XML file.
      - "Tasks show up in the report as follows:
        'ok': pass
        'failed' with 'EXPECTED FAILURE' in the task name: pass
        'failed' with 'TOGGLE RESULT' in the task name: pass
        'ok' with 'TOGGLE RESULT' in the task name: failure
        'failed' due to an exception: error
        'failed' for other reasons: failure
        'skipped': skipped"
    options:
      output_dir:
        name: JUnit output dir
        default: ~/.ansible.log
        description: Directory to write XML files to.
        env:
          - name: JUNIT_OUTPUT_DIR
      task_class:
        name: JUnit Task class
        default: False
        description: Configure the output to be one class per yaml file
        env:
          - name: JUNIT_TASK_CLASS
      task_relative_path:
        name: JUnit Task relative path
        default: none
        description: Configure the output to use relative paths to given directory
        version_added: "2.8"
        env:
          - name: JUNIT_TASK_RELATIVE_PATH
      replace_out_of_tree_path:
        name: Replace out of tree path
        default: none
        description: Replace the directory portion of an out-of-tree relative task path with the given placeholder
        version_added: "2.12.3"
        env:
          - name: JUNIT_REPLACE_OUT_OF_TREE_PATH
      fail_on_change:
        name: JUnit fail on change
        default: False
        description: Consider any tasks reporting "changed" as a junit test failure
        env:
          - name: JUNIT_FAIL_ON_CHANGE
      fail_on_ignore:
        name: JUnit fail on ignore
        default: False
        description: Consider failed tasks as a junit test failure even if ignore_on_error is set
        env:
          - name: JUNIT_FAIL_ON_IGNORE
      include_setup_tasks_in_report:
        name: JUnit include setup tasks in report
        default: True
        description: Should the setup tasks be included in the final report
        env:
          - name: JUNIT_INCLUDE_SETUP_TASKS_IN_REPORT
      hide_task_arguments:
        name: Hide the arguments for a task
        default: False
        description: Hide the arguments for a task
        version_added: "2.8"
        env:
          - name: JUNIT_HIDE_TASK_ARGUMENTS
      test_case_prefix:
        name: Prefix to find actual test cases
        default: <empty>
        description: Consider a task only as test case if it has this value as prefix. Additionally failing tasks are recorded as failed test cases.
        version_added: "2.8"
        env:
          - name: JUNIT_TEST_CASE_PREFIX
    requirements:
      - enable in configuration
N)	constants)to_bytesto_text)CallbackBase)TestCase	TestErrorTestFailure	TestSuite
TestSuitesc                       e Zd ZdZdZdZdZdZ fdZd Z	d Z
d	 Zd
 Zd Zd Zd Zd Zd Zd Zd ZddZd Zd Zd Zd Z xZS )CallbackModulea  
    This callback writes playbook output to a JUnit formatted XML file.

    Tasks show up in the report as follows:
        'ok': pass
        'failed' with 'EXPECTED FAILURE' in the task name: pass
        'failed' with 'TOGGLE RESULT' in the task name: pass
        'ok' with 'TOGGLE RESULT' in the task name: failure
        'failed' due to an exception: error
        'failed' for other reasons: failure
        'skipped': skipped

    This plugin makes use of the following environment variables:
        JUNIT_OUTPUT_DIR (optional): Directory to write XML files to.
                                     Default: ~/.ansible.log
        JUNIT_TASK_CLASS (optional): Configure the output to be one class per yaml file
                                     Default: False
        JUNIT_TASK_RELATIVE_PATH (optional): Configure the output to use relative paths to given directory
                                     Default: none
        JUNIT_FAIL_ON_CHANGE (optional): Consider any tasks reporting "changed" as a junit test failure
                                     Default: False
        JUNIT_FAIL_ON_IGNORE (optional): Consider failed tasks as a junit test failure even if ignore_on_error is set
                                     Default: False
        JUNIT_INCLUDE_SETUP_TASKS_IN_REPORT (optional): Should the setup tasks be included in the final report
                                     Default: True
        JUNIT_HIDE_TASK_ARGUMENTS (optional): Hide the arguments for a task
                                     Default: False
        JUNIT_TEST_CASE_PREFIX (optional): Consider a task only as test case if it has this value as prefix. Additionally failing tasks are recorded as failed
                                     test cases.
                                     Default: <empty>
    g       @	aggregatejunitTc                   t         t        |           t        j                  dt        j
                  j                  d            | _        t        j                  dd      j                         | _	        t        j                  dd      | _
        t        j                  dd      j                         | _        t        j                  dd      j                         | _        t        j                  d	d
      j                         | _        t        j                  dd      j                         | _        t        j                  dd      | _        t        j                  dd       | _        d | _        d | _        d | _        d | _        d| _        i | _        | j                   t-        | j                         | _        t        j
                  j/                  | j                        s t        j0                  | j                         y y )NJUNIT_OUTPUT_DIRz~/.ansible.logJUNIT_TASK_CLASSFalseJUNIT_TASK_RELATIVE_PATH JUNIT_FAIL_ON_CHANGEJUNIT_FAIL_ON_IGNORE#JUNIT_INCLUDE_SETUP_TASKS_IN_REPORTTrueJUNIT_HIDE_TASK_ARGUMENTSJUNIT_TEST_CASE_PREFIXJUNIT_REPLACE_OUT_OF_TREE_PATHF)superr   __init__osgetenvpath
expanduser_output_dirlower_task_class_task_relative_path_fail_on_change_fail_on_ignore_include_setup_tasks_in_report_hide_task_arguments_test_case_prefix_replace_out_of_tree_path_playbook_path_playbook_name
_play_name
_task_datadisabledr   existsmakedirs)self	__class__s    N/home/dcms/DCMS/lib/python3.12/site-packages/ansible/plugins/callback/junit.pyr   zCallbackModule.__init__   s{   nd,.99%79K9KL\9]^99%7AGGI#%99-G#L !yy)?IOOQ!yy)?IOOQ.0ii8]_e.f.l.l.n+$&II.I7$S$Y$Y$[!!#+CR!H)+3SUY)Z&""))5-4T5S5S-TD*ww~~d../KK(() 0    c                   |j                   }|| j                  v ry| j                  }|j                         j	                         }|j                         }|j                  }|j                  sI| j                  dk(  r:dj                  d |j                  j                         D              }|r|d|z   z  }t        |||||      | j                  |<   y)z2 record the start of a task for one or more hosts Nfalsez, c              3  &   K   | ]	  }d |z    yw)z%s=%sN ).0as     r7   	<genexpr>z-CallbackModule._start_task.<locals>.<genexpr>   s     EagkEs    )_uuidr1   r0   get_namestripget_pathactionno_logr+   joinargsitemsTaskData)r5   taskuuidplaynamer"   rE   rH   s           r7   _start_taskzCallbackModule._start_task   s     zz4??"}}$$&}}{{t88GC99E499??3DEFDd
" (tT4 Hr8   c                "   |j                   j                  }t        |d      r-|j                  j                  }|j                  j                  }nd}d}| j
                  |   }| j                  dk(  r#|dk(  r|j                  j                  dd      rd}|dk(  rd|j                  v rd}nd	|j                  v r|dk(  rd}n|dk(  rd}|j                  j                  | j                        s|dk(  r|j                  t        ||||             y
y
)z0 record the results of a task for a single host _hostincludetrueokchangedFfailedzEXPECTED FAILUREzTOGGLE RESULTN)_taskrA   hasattrrQ   rN   r1   r(   _resultget
startswithr,   add_hostHostData)r5   statusresult	task_uuid	host_uuid	host_name	task_datas          r7   _finish_taskzCallbackModule._finish_task   s     LL&&	67#**I))I!I!IOOI.	6)fnASAST]_dAeF X"4	"FF	.!4!>>$$T%;%;<(@Rx	9ffMN ASr8   c                   d|j                   d|j                  d|j                   }|j                  |j                  z
  }| j                  r\|j
                  rPt        t        j
                  j                  t        |j
                        t        | j                                    }n|j
                  }| j                  O|j                  d      r>| j                  t        t        j
                  j                  t        |                  z   }| j                  dk(  rt        j                  dd|      }|j                   dk(  r"t#        |||t%        |j&                        	      S |j&                  j(                  }|j+                  d
d      }| j-                  |d      }| j/                  |      }|j                   dk(  rt#        ||||	      S t#        |||      }	|j                   dk(  rd|v rR|d   j1                         j3                  d      d   }
|d   }|	j4                  j7                  t9        |
|             |	S d|v r-|d   }
|	j:                  j7                  t=        |
|             |	S |	j:                  j7                  t=        d|z  |             |	S |j                   dk(  rd|v r|d   }
nd}
|
|	_        |	S )z7 build a TestCase from the given TaskData and HostData [z] : z../rS   z\.yml:[0-9]+$r   included)rN   	classnametime
system_outrcr   )indentrT   )rN   ri   rj   rV   	exception
)messageoutputmsgzrc=%sskippedskip_reason) rN   rM   finishstartr'   r"   r   r    relpathr   r-   r[   basenamer&   resubr^   r   strr_   rY   rZ   _dump_results_cleanse_stringrC   spliterrorsappendr	   failuresr
   rt   )r5   rc   	host_datarN   durationjunit_classnameresrl   dump	test_caserq   rr   s               r7   _build_test_casezCallbackModule._build_test_case   sw    !*		O##ioo5##	%bggoohy~~6NPXY]YqYqPr&stO'nnO))5/:T:TUZ:["<<wrwwGWGWX`apXqGr?ssOv% ff%5r?KOz)x\_`i`p`p\qrr&&WWT1!!#a!0##D)t#x\`aa$/Q	x'c!k*00288>rB[)  ''	'&(QR  #e*""))+gd*ST  ""))+glSW*XY  *#m,# 'Ir8   c                2    t        t        |d      d      S )z] convert surrogate escapes to the unicode replacement character to avoid XML encoding errors surrogateescaper   replace)r   r   )r5   values     r7   r~   zCallbackModule._cleanse_string  s    x.?@SSr8   c                   g }| j                   j                         D ]t  \  }}|j                  t        j                  v r| j
                  dk(  r2|j                  j                         D ]&  \  }}|j                  | j                  ||             ( v t        | j                  |      }t        |g      }|j                         }t        j                  j                  | j                   | j                  dt#        j"                         d      }	t%        |	d      5 }
|
j'                  t)        |d             d	d	d	       y	# 1 sw Y   y	xY w)
zF generate a TestSuite report from the collected TaskData and HostData r:   )rN   cases)suites-z.xmlwbsurrogate_or_strictr   N)r1   rI   rE   C_ACTION_SETUPr*   r   r   r   r   r/   r   to_pretty_xmlr    r"   rG   r$   rj   openwriter   )r5   
test_casesr`   rc   ra   r   
test_suitetest_suitesreportoutput_filexmls              r7   _generate_reportzCallbackModule._generate_report  s%    
$(OO$9$9$; 	O Iy1??2t7Z7Z^e7e(1(;(;(A(A(C O$	9!!$"7"7	9"MNO		O D$7$7zJ
 5**,ggll4#3#3DDWDWY]YbYbYd5ef+t$ 	FIIhv.CDE	F 	F 	Fs    EEc                    |j                   | _        t        j                  j	                  t        j                  j                  | j                              d   | _        y )Nr   )
_file_namer.   r    r"   splitextry   r/   )r5   playbooks     r7   v2_playbook_on_startz#CallbackModule.v2_playbook_on_start!  sB    &11 gg..rww/?/?@S@S/TUVWXr8   c                .    |j                         | _        y N)rB   r0   )r5   rM   s     r7   v2_playbook_on_play_startz(CallbackModule.v2_playbook_on_play_start%  s    --/r8   c                &    | j                  |       y r   rO   r5   rK   s     r7   v2_runner_on_no_hostsz$CallbackModule.v2_runner_on_no_hosts(      r8   c                &    | j                  |       y r   r   )r5   rK   is_conditionals      r7   v2_playbook_on_task_startz(CallbackModule.v2_playbook_on_task_start+  r   r8   c                &    | j                  |       y r   r   r   s     r7   !v2_playbook_on_cleanup_task_startz0CallbackModule.v2_playbook_on_cleanup_task_start.  r   r8   c                &    | j                  |       y r   r   r   s     r7   !v2_playbook_on_handler_task_startz0CallbackModule.v2_playbook_on_handler_task_start1  r   r8   c                p    |r"| j                   dk7  r| j                  d|       y | j                  d|       y )NrS   rT   rV   )r)   rd   )r5   r_   ignore_errorss      r7   v2_runner_on_failedz"CallbackModule.v2_runner_on_failed4  s2    T11V;dF+h/r8   c                (    | j                  d|       y )NrT   rd   r5   r_   s     r7   v2_runner_on_okzCallbackModule.v2_runner_on_ok:  s    $'r8   c                (    | j                  d|       y )Nrt   r   r   s     r7   v2_runner_on_skippedz#CallbackModule.v2_runner_on_skipped=  s    )V,r8   c                (    | j                  d|       y )Nrh   r   )r5   included_files     r7   v2_playbook_on_includez%CallbackModule.v2_playbook_on_include@  s    *m4r8   c                $    | j                          y r   )r   )r5   statss     r7   v2_playbook_on_statsz#CallbackModule.v2_playbook_on_statsC  s    r8   )F)__name__
__module____qualname____doc__CALLBACK_VERSIONCALLBACK_TYPECALLBACK_NAMECALLBACK_NEEDS_ENABLEDr   rO   rd   r   r~   r   r   r   r   r   r   r   r   r   r   r   r   __classcell__)r6   s   @r7   r   r   e   s|    @ MM!*6I(O:/bTF*Y*0(-5 r8   r   c                      e Zd ZdZd Zd Zy)rJ   z(
    Data about an individual task.
    c                    || _         || _        || _        || _        d | _        i | _        t        j                         | _        || _        y r   )rL   rN   r"   rM   rw   r   rj   rE   )r5   rL   rN   r"   rM   rE   s         r7   r   zTaskData.__init__L  s@    				
YY[
r8   c           	     p   |j                   | j                  v r|j                  dk(  r8| j                  |j                      j                  d|j                  |_        n>t	        | j
                  d| j                  d| j                  d|j                        || j                  |j                   <   y )Nrh   ro   rg   z: duplicate host callback: )rL   r   r^   r_   	Exceptionr"   rM   rN   )r5   hosts     r7   r\   zTaskData.add_hostV  s    99&{{j(*...*C*J*JDKKXTYYX\XaXacgclclnrnwnw xyy$(tyy!r8   N)r   r   r   r   r   r\   r<   r8   r7   rJ   rJ   G  s    )r8   rJ   c                      e Zd ZdZd Zy)r]   z(
    Data about an individual host.
    c                n    || _         || _        || _        || _        t	        j                         | _        y r   )rL   rN   r^   r_   rj   rv   )r5   rL   rN   r^   r_   s        r7   r   zHostData.__init__f  s+    		iikr8   N)r   r   r   r   r   r<   r8   r7   r]   r]   a  s    "r8   r]   )
__future__r   DOCUMENTATIONr    rj   rz   ansibler   r   +ansible.module_utils.common.text.convertersr   r   ansible.plugins.callbackr   ansible.utils._junit_xmlr   r	   r
   r   r   r   rJ   r]   r<   r8   r7   <module>r      sT   
 #L\ 
  	 " I 1 _ \ _ D) )4
" 
"r8   