Fix up coverage with async on Windows (#84917)

Fixes the coverage collection for Windows and async tasks. This ensures
the async task still has access to the PSHost so that it can access the
runspace debugger tasks on the host.
pull/84796/merge
Jordan Borean 8 months ago committed by GitHub
parent 390e112822
commit b7d76a93b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -4,6 +4,7 @@
using namespace Microsoft.Win32.SafeHandles
using namespace System.Collections
using namespace System.IO
using namespace System.Management.Automation
using namespace System.Text
using namespace System.Threading
@ -43,6 +44,15 @@ param([ScriptBlock]$ScriptBlock, $Param)
Param = $execInfo.Parameters
})
# It is important we run with the invocation settings so that it has access
# to the same PSHost. The pipeline input also needs to be marked as complete
# so the exec_wrapper isn't waiting for input indefinitely.
$pipelineInput = [PSDataCollection[object]]::new()
$pipelineInput.Complete()
$invocationSettings = [PSInvocationSettings]@{
Host = $host
}
# Signals async_wrapper that we are ready to start the job and to stop waiting
$waitHandle = [SafeWaitHandle]::new([IntPtr]$WaitHandleId, $true)
$waitEvent = [ManualResetEvent]::new($false)
@ -52,7 +62,7 @@ $null = $waitEvent.Set()
$jobOutput = $null
$jobError = $null
try {
$jobAsyncResult = $ps.BeginInvoke()
$jobAsyncResult = $ps.BeginInvoke($pipelineInput, $invocationSettings, $null, $null)
$jobAsyncResult.AsyncWaitHandle.WaitOne($Timeout * 1000) > $null
$result.finished = 1

@ -0,0 +1,9 @@
Function Test-CollectionPwshCoverage {
<#
.SYNOPSIS
Test coverage for collection pwsh util.
#>
'foo'
}
Export-ModuleMember -Function Test-CollectionPwshCoverage

@ -1,6 +1,8 @@
#!powershell
#AnsibleRequires -CSharpUtil Ansible.Basic
#AnsibleRequires -PowerShell ..module_utils.CollectionPwshCoverage
$module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
$module.Result.util = Test-CollectionPwshCoverage
$module.ExitJson()

@ -0,0 +1,6 @@
#!powershell
#AnsibleRequires -CSharpUtil Ansible.Basic
$module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
$module.ExitJson()

@ -0,0 +1,8 @@
#!powershell
#AnsibleRequires -CSharpUtil Ansible.Basic
#AnsibleRequires -PowerShell Ansible.ModuleUtils.AdjacentPwshCoverage
$module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
$module.Result.util = Test-AdjacentPwshCoverage
$module.ExitJson()

@ -0,0 +1,9 @@
Function Test-AdjacentPwshCoverage {
<#
.SYNOPSIS
Test coverage for module_util adjacent pwsh util.
#>
'foo'
}
Export-ModuleMember -Function Test-AdjacentPwshCoverage

@ -2,4 +2,21 @@
win_collection:
- name: run module in library adjacent to test coverage for test plugins
test_win_collection:
test_win_collection_normal:
register: library_result
- name: assert run module with library adjacent module
assert:
that:
- library_result.util == 'foo'
- name: test coverage under async
test_win_collection_async:
async: 30
poll: 2
- name: test coverage under become
test_win_collection_become:
become: yes
become_method: runas
become_user: SYSTEM

@ -3,24 +3,42 @@ from __future__ import annotations
import json
import os
import os.path
import pathlib
def main() -> None:
collection_root = os.getcwd()
collection_root = pathlib.Path(os.getcwd())
print(f"Running windows-integration coverage test in '{collection_root}'")
result_path = os.path.join(collection_root, "tests", "output", "coverage", "coverage-powershell")
module_path = os.path.join(collection_root, "plugins", "modules", "win_collection.ps1")
test_path = os.path.join(collection_root, "tests", "integration", "targets", "win_collection", "library", "test_win_collection.ps1")
result_path = collection_root / "tests" / "output" / "coverage" / "coverage-powershell"
adjacent_modules_path = collection_root / "tests" / "integration" / "targets" / "win_collection" / "library"
adjacent_utils_path = collection_root / "tests" / "integration" / "targets" / "win_collection" / "module_utils"
collection_modules_path = collection_root / "plugins" / "modules"
collection_utils_path = collection_root / "plugins" / "module_utils"
expected_hits = {
str(adjacent_modules_path / 'test_win_collection_async.ps1'): {'5': 1, '6': 1},
str(adjacent_modules_path / 'test_win_collection_become.ps1'): {'5': 1, '6': 1},
str(adjacent_modules_path / 'test_win_collection_normal.ps1'): {'6': 1, '7': 1, '8': 1},
str(adjacent_utils_path / 'Ansible.ModuleUtils.AdjacentPwshCoverage.psm1'): {'6': 1, '9': 1},
str(collection_modules_path / 'win_collection.ps1'): {'6': 1, '7': 1, '8': 1},
str(collection_utils_path / 'CollectionPwshCoverage.psm1'): {'6': 1, '9': 1},
}
found_hits = set()
with open(result_path, mode="rb") as fd:
data = json.load(fd)
for path, result in data.items():
print(f"Testing result for path '{path}' -> {result!r}")
assert path in [module_path, test_path], f"Found unexpected coverage result path '{path}'"
assert result == {'5': 1, '6': 1}, "Coverage result did not pick up a hit on lines 5 and 6"
assert path in expected_hits, f"Found unexpected coverage result path '{path}'"
expected = expected_hits[path]
assert result == expected, f"Coverage result for {path} was {result!r} but was expecting {expected!r}"
found_hits.add(path)
assert len(data) == 2, f"Expected coverage results for 2 files but got {len(data)}"
missing_hits = set(expected_hits.keys()).difference(found_hits)
assert not missing_hits, f"Expected coverage results for {', '.join(missing_hits)} but they were not present"
if __name__ == '__main__':

Loading…
Cancel
Save