diff options
Diffstat (limited to 'test/integration/targets/win_async_wrapper')
3 files changed, 307 insertions, 0 deletions
diff --git a/test/integration/targets/win_async_wrapper/aliases b/test/integration/targets/win_async_wrapper/aliases new file mode 100644 index 0000000..59dda5e --- /dev/null +++ b/test/integration/targets/win_async_wrapper/aliases @@ -0,0 +1,3 @@ +async_status +shippable/windows/group1 +shippable/windows/smoketest diff --git a/test/integration/targets/win_async_wrapper/library/async_test.ps1 b/test/integration/targets/win_async_wrapper/library/async_test.ps1 new file mode 100644 index 0000000..3b4c1c8 --- /dev/null +++ b/test/integration/targets/win_async_wrapper/library/async_test.ps1 @@ -0,0 +1,47 @@ +#!powershell + +# Copyright: (c) 2018, Ansible Project + +#Requires -Module Ansible.ModuleUtils.Legacy + +$parsed_args = Parse-Args $args + +$sleep_delay_sec = Get-AnsibleParam -obj $parsed_args -name "sleep_delay_sec" -type "int" -default 0 +$fail_mode = Get-AnsibleParam -obj $parsed_args -name "fail_mode" -type "str" -default "success" -validateset "success", "graceful", "exception" + +If ($fail_mode -isnot [array]) { + $fail_mode = @($fail_mode) +} + +$result = @{ + changed = $true + module_pid = $pid + module_tempdir = $PSScriptRoot +} + +If ($sleep_delay_sec -gt 0) { + Sleep -Seconds $sleep_delay_sec + $result["slept_sec"] = $sleep_delay_sec +} + +If ($fail_mode -contains "leading_junk") { + Write-Output "leading junk before module output" +} + +If ($fail_mode -contains "graceful") { + Fail-Json $result "failed gracefully" +} + +Try { + + If ($fail_mode -contains "exception") { + Throw "failing via exception" + } + + Exit-Json $result +} +Finally { + If ($fail_mode -contains "trailing_junk") { + Write-Output "trailing junk after module output" + } +} diff --git a/test/integration/targets/win_async_wrapper/tasks/main.yml b/test/integration/targets/win_async_wrapper/tasks/main.yml new file mode 100644 index 0000000..91b4584 --- /dev/null +++ b/test/integration/targets/win_async_wrapper/tasks/main.yml @@ -0,0 +1,257 @@ +- name: capture timestamp before fire and forget + set_fact: + start_timestamp: "{{ lookup('pipe', 'date +%s') }}" + +- name: async fire and forget + async_test: + sleep_delay_sec: 15 + async: 20 + poll: 0 + register: asyncresult + +- name: validate response + assert: + that: + - asyncresult.ansible_job_id is match('\d+\.\d+') + - asyncresult.started == 1 + - asyncresult is started + - asyncresult.finished == 0 + - asyncresult is not finished + - asyncresult.results_file is search('\.ansible_async.+\d+\.\d+') + # ensure that async is actually async- this test will fail if # hosts > forks or if the target host is VERY slow + - (lookup('pipe', 'date +%s') | int) - (start_timestamp | int) < 15 + +- name: async poll immediate success + async_test: + sleep_delay_sec: 0 + async: 10 + poll: 1 + register: asyncresult + +- name: validate response + assert: + that: + - asyncresult.ansible_job_id is match('\d+\.\d+') + - asyncresult.finished == 1 + - asyncresult is finished + - asyncresult is changed + - asyncresult.ansible_async_watchdog_pid is number +# - asyncresult.module_tempdir is search('ansible-tmp-') + - asyncresult.module_pid is number + +# this part of the test is flaky- Windows PIDs are reused aggressively, so this occasionally fails due to a new process with the same ID +# FUTURE: consider having the test module hook to a kernel object we can poke at that gets signaled/released on exit +#- name: ensure that watchdog and module procs have exited +# raw: Get-Process | Where { $_.Id -in ({{ asyncresult.ansible_async_watchdog_pid }}, {{ asyncresult.module_pid }}) } +# register: proclist +# +#- name: validate no running watchdog/module processes were returned +# assert: +# that: +# - proclist.stdout.strip() == '' + +#- name: ensure that module_tempdir was deleted +# raw: Test-Path {{ asyncresult.module_tempdir }} +# register: tempdircheck +# +#- name: validate tempdir response +# assert: +# that: +# - tempdircheck.stdout is search('False') + +- name: async poll retry + async_test: + sleep_delay_sec: 5 + async: 10 + poll: 1 + register: asyncresult + +- name: validate response + assert: + that: + - asyncresult.ansible_job_id is match('\d+\.\d+') + - asyncresult.finished == 1 + - asyncresult is finished + - asyncresult is changed +# - asyncresult.module_tempdir is search('ansible-tmp-') + - asyncresult.module_pid is number + +# this part of the test is flaky- Windows PIDs are reused aggressively, so this occasionally fails due to a new process with the same ID +# FUTURE: consider having the test module hook to a kernel object we can poke at that gets signaled/released on exit +#- name: ensure that watchdog and module procs have exited +# raw: Get-Process | Where { $_.Id -in ({{ asyncresult.ansible_async_watchdog_pid }}, {{ asyncresult.module_pid }}) } +# register: proclist +# +#- name: validate no running watchdog/module processes were returned +# assert: +# that: +# - proclist.stdout.strip() == '' + +#- name: ensure that module_tempdir was deleted +# raw: Test-Path {{ asyncresult.module_tempdir }} +# register: tempdircheck +# +#- name: validate tempdir response +# assert: +# that: +# - tempdircheck.stdout is search('False') + +- name: async poll timeout + async_test: + sleep_delay_sec: 5 + async: 3 + poll: 1 + register: asyncresult + ignore_errors: true + +- name: validate response + assert: + that: + - asyncresult.ansible_job_id is match('\d+\.\d+') + - asyncresult.finished == 1 + - asyncresult is finished + - asyncresult is not changed + - asyncresult is failed + - asyncresult.msg is search('timed out') + +- name: async poll graceful module failure + async_test: + fail_mode: graceful + async: 5 + poll: 1 + register: asyncresult + ignore_errors: true + +- name: validate response + assert: + that: + - asyncresult.ansible_job_id is match('\d+\.\d+') + - asyncresult.finished == 1 + - asyncresult is finished + - asyncresult is changed + - asyncresult is failed + - asyncresult.msg == 'failed gracefully' + +- name: async poll exception module failure + async_test: + fail_mode: exception + async: 5 + poll: 1 + register: asyncresult + ignore_errors: true + +- name: validate response + assert: + that: + - asyncresult.ansible_job_id is match('\d+\.\d+') + - asyncresult.finished == 1 + - asyncresult is finished + - asyncresult is not changed + - asyncresult is failed + - 'asyncresult.msg == "Unhandled exception while executing module: failing via exception"' + +- name: echo some non ascii characters + win_command: cmd.exe /c echo über den Fußgängerübergang gehen + async: 10 + poll: 1 + register: nonascii_output + +- name: assert echo some non ascii characters + assert: + that: + - nonascii_output is changed + - nonascii_output.rc == 0 + - nonascii_output.stdout_lines|count == 1 + - nonascii_output.stdout_lines[0] == 'über den Fußgängerübergang gehen' + - nonascii_output.stderr == '' + +- name: test async with custom async dir + win_shell: echo hi + register: async_custom_dir + async: 5 + vars: + ansible_async_dir: '{{win_output_dir}}' + +- name: assert results file is in the remote tmp specified + assert: + that: + - async_custom_dir.results_file == win_output_dir + '\\' + async_custom_dir.ansible_job_id + +- name: test async fire and forget with custom async dir + win_shell: echo hi + register: async_custom_dir_poll + async: 5 + poll: 0 + vars: + ansible_async_dir: '{{win_output_dir}}' + +- name: poll with different dir - fail + async_status: + jid: '{{ async_custom_dir_poll.ansible_job_id }}' + register: fail_async_custom_dir_poll + ignore_errors: yes + +- name: poll with different dir - success + async_status: + jid: '{{ async_custom_dir_poll.ansible_job_id }}' + register: success_async_custom_dir_poll + vars: + ansible_async_dir: '{{win_output_dir}}' + +- name: assert test async fire and forget with custom async dir + assert: + that: + - fail_async_custom_dir_poll.failed + - '"could not find job at ''" + nonascii_output.results_file|win_dirname + "''" in fail_async_custom_dir_poll.msg' + - not success_async_custom_dir_poll.failed + - success_async_custom_dir_poll.results_file == win_output_dir + '\\' + async_custom_dir_poll.ansible_job_id + +# FUTURE: figure out why the last iteration of this test often fails on shippable +#- name: loop async success +# async_test: +# sleep_delay_sec: 3 +# async: 10 +# poll: 0 +# with_sequence: start=1 end=4 +# register: async_many +# +#- name: wait for completion +# async_status: +# jid: "{{ item }}" +# register: asyncout +# until: asyncout is finished +# retries: 10 +# delay: 1 +# with_items: "{{ async_many.results | map(attribute='ansible_job_id') | list }}" +# +#- name: validate results +# assert: +# that: +# - item.finished == 1 +# - item is finished +# - item.slept_sec == 3 +# - item is changed +# - item.ansible_job_id is match('\d+\.\d+') +# with_items: "{{ asyncout.results }}" + +# this part of the test is flaky- Windows PIDs are reused aggressively, so this occasionally fails due to a new process with the same ID +# FUTURE: consider having the test module hook to a kernel object we can poke at that gets signaled/released on exit +#- name: ensure that all watchdog and module procs have exited +# raw: Get-Process | Where { $_.Id -in ({{ asyncout.results | join(',', attribute='ansible_async_watchdog_pid') }}, {{ asyncout.results | join(',', attribute='module_pid') }}) } +# register: proclist +# +#- name: validate no processes were returned +# assert: +# that: +# - proclist.stdout.strip() == "" + +# FUTURE: test junk before/after JSON +# FUTURE: verify tempdir stays through module exec +# FUTURE: verify tempdir is deleted after module exec +# FUTURE: verify tempdir is permanent with ANSIBLE_KEEP_REMOTE_FILES=1 (how?) +# FUTURE: verify binary modules work + +# FUTURE: test status/return +# FUTURE: test status/cleanup +# FUTURE: test reboot/connection failure +# FUTURE: figure out how to ensure that processes and tempdirs are cleaned up in all exceptional cases |