o nnh5@sddlmZdZddlZddlZddlZddlmZddl m Z m Z ddl m Z ddlmZmZmZmZmZGdd d e ZGd d d ZGd d d ZdS)) 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: 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_bytesto_text) CallbackBase)TestCase TestError TestFailure TestSuite TestSuitescseZdZdZdZdZdZdZfddZdd Z d d Z d d Z ddZ ddZ ddZddZddZddZddZddZd)dd Zd!d"Zd#d$Zd%d&Zd'd(ZZS)*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: g@ aggregatejunitTcstt|tdtjd|_tdd|_ tdd|_ tdd|_ tdd|_ td d |_ td d|_td d|_td d|_d|_d|_d|_d|_d|_i|_|jdurqt|j|_tj|jst|jdSdS)NJUNIT_OUTPUT_DIRz~/.ansible.logJUNIT_TASK_CLASSFalseJUNIT_TASK_RELATIVE_PATHJUNIT_FAIL_ON_CHANGEJUNIT_FAIL_ON_IGNORE#JUNIT_INCLUDE_SETUP_TASKS_IN_REPORTTrueJUNIT_HIDE_TASK_ARGUMENTSJUNIT_TEST_CASE_PREFIXJUNIT_REPLACE_OUT_OF_TREE_PATHF)superr __init__osgetenvpath expanduser _output_dirlower _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_datadisabledrexistsmakedirs)self __class__I/usr/local/lib/python3.10/dist-packages/ansible/plugins/callback/junit.pyrs*  zCallbackModule.__init__cCs|j}||jvr dS|j}|}|}|j}|js7|jdkr7d dd|j D}|r7|d|7}t ||||||j|<dS)z2 record the start of a task for one or more hosts Nfalsez, css|]}d|VqdS)z%s=%sNr5).0ar5r5r6 sz-CallbackModule._start_task.. ) _uuidr.r-get_namestripget_pathactionno_logr(joinargsitemsTaskData)r2taskuuidplaynamerr@rCr5r5r6 _start_tasks   zCallbackModule._start_taskcCs|jj}t|dr|jj}|jj}nd}d}|j|}|jdkr-|dkr-|jddr-d}|dkr9d|jvr9d}nd |jvrK|dkrEd}n|dkrKd}|j |j sV|dkrb| t ||||d Sd S) z0 record the results of a task for a single host _hostincludetrueokchangedFfailedzEXPECTED FAILUREz TOGGLE RESULTN) _taskr<hasattrrKrIr.r%_resultget startswithr)add_hostHostData)r2statusresult task_uuid host_uuid host_name task_datar5r5r6 _finish_tasks&     zCallbackModule._finish_taskc Csd|j|j|jf}|j|j}|jr&|jr&ttjt |jt |j}n|j}|j dur@| dr@|j ttj t |}|j dkrLtdd|}|jdkr\t|||t|jdS|jj}|d d }|j|d d }||}|jd krt||||dSt|||d } |jdkrd|vr|ddd} |d} | jt| | d| Sd|vr|d} | jt| |d| S| jtd||d| S|jdkrd|vr|d} nd} | | _| S)z7 build a TestCase from the given TaskData and HostData z [%s] %s: %sNz../rMz \.yml:[0-9]+$rincluded)rI classnametime system_outrcr)indentrN)rIr`rarP exception )messageoutputmsgzrc=%sskipped skip_reason) rIrHfinishstartr$rrrrelpathrr*rUbasenamer#resubrXrstrrYrSrT _dump_results_cleanse_stringr>spliterrorsappendrfailuresr rk) r2r] host_datarIdurationjunit_classnameresrcdump test_caserhrir5r5r6_build_test_casesH             zCallbackModule._build_test_casecCstt|ddddS)z] convert surrogate escapes to the unicode replacement character to avoid XML encoding errors surrogateescaperwreplace)rr)r2valuer5r5r6ruszCallbackModule._cleanse_stringc Csg}|jD]#\}}|jtjvr|jdkrq|jD] \}}||||qqt |j |d}t |gd}| }t j|jd|j tf} t| d} | t|ddWddS1sewYdS) zF generate a TestSuite report from the collected TaskData and HostData r7)rIcases)suitesz %s-%s.xmlwbsurrogate_or_strictrN)r.rDr@C _ACTION_SETUPr'rzrxrr r,r to_pretty_xmlrrrBr!raopenwriter) r2 test_casesrZr]r[rz test_suite test_suitesreport output_filexmlr5r5r6_generate_report s  "zCallbackModule._generate_reportcCs(|j|_tjtj|jd|_dS)Nr) _file_namer+rrsplitextrpr,)r2playbookr5r5r6v2_playbook_on_start!s z#CallbackModule.v2_playbook_on_startcCs||_dSN)r=r-)r2rHr5r5r6v2_playbook_on_play_start%z(CallbackModule.v2_playbook_on_play_startcC||dSrrJr2rFr5r5r6v2_runner_on_no_hosts(rz$CallbackModule.v2_runner_on_no_hostscCrrr)r2rFis_conditionalr5r5r6v2_playbook_on_task_start+rz(CallbackModule.v2_playbook_on_task_startcCrrrrr5r5r6!v2_playbook_on_cleanup_task_start.rz0CallbackModule.v2_playbook_on_cleanup_task_startcCrrrrr5r5r6!v2_playbook_on_handler_task_start1rz0CallbackModule.v2_playbook_on_handler_task_startFcCs.|r|jdkr|d|dS|d|dS)NrMrNrP)r&r^)r2rY ignore_errorsr5r5r6v2_runner_on_failed4sz"CallbackModule.v2_runner_on_failedcC|d|dS)NrNr^r2rYr5r5r6v2_runner_on_ok:zCallbackModule.v2_runner_on_okcCr)Nrkrrr5r5r6v2_runner_on_skipped=rz#CallbackModule.v2_runner_on_skippedcCr)Nr_r)r2 included_filer5r5r6v2_playbook_on_include@rz%CallbackModule.v2_playbook_on_includecCs |dSr)r)r2statsr5r5r6v2_playbook_on_statsCs z#CallbackModule.v2_playbook_on_stats)F)__name__ __module__ __qualname____doc__CALLBACK_VERSION CALLBACK_TYPE CALLBACK_NAMECALLBACK_NEEDS_ENABLEDrrJr^rrurrrrrrrrrrrr __classcell__r5r5r3r6r es.  1 r c@s eZdZdZddZddZdS)rEz( Data about an individual task. cCs8||_||_||_||_d|_i|_t|_||_dSr)rGrIrrHrnrzrar@)r2rGrIrrHr@r5r5r6rLs  zTaskData.__init__cCs^|j|jvr'|jdkrd|j|jj|jf|_ntd|j|j|j|jf||j|j<dS)Nr_z%s %sz'%s: %s: %s: duplicate host callback: %s)rGrzrXrY ExceptionrrHrI)r2hostr5r5r6rVVs  zTaskData.add_hostN)rrrrrrVr5r5r5r6rEGs rEc@seZdZdZddZdS)rWz( Data about an individual host. cCs&||_||_||_||_t|_dSr)rGrIrXrYrarm)r2rGrIrXrYr5r5r6rfs zHostData.__init__N)rrrrrr5r5r5r6rWas rW) __future__r DOCUMENTATIONrrarqansiblerr+ansible.module_utils.common.text.convertersrransible.plugins.callbackransible.utils._junit_xmlrrr r r r rErWr5r5r5r6s N   c