From e875e91363f58396777aad6f7cdb04f8a813b5cd Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Tue, 18 May 2021 03:00:06 +1000 Subject: [PATCH] ansible-test - use pwsh to generate stubs (#74271) --- changelogs/fragments/coverage-pwsh-stubs.yml | 2 + test/lib/ansible_test/_data/coverage_stub.ps1 | 38 +++++++++++++++++++ .../_internal/commands/coverage/combine.py | 25 +++++++----- 3 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 changelogs/fragments/coverage-pwsh-stubs.yml create mode 100644 test/lib/ansible_test/_data/coverage_stub.ps1 diff --git a/changelogs/fragments/coverage-pwsh-stubs.yml b/changelogs/fragments/coverage-pwsh-stubs.yml new file mode 100644 index 00000000000..91aa52deb14 --- /dev/null +++ b/changelogs/fragments/coverage-pwsh-stubs.yml @@ -0,0 +1,2 @@ +bugfixes: +- ansible-test - Use pwsh to generate correct coverage line counts for stub files to get a more accurate coverage result diff --git a/test/lib/ansible_test/_data/coverage_stub.ps1 b/test/lib/ansible_test/_data/coverage_stub.ps1 new file mode 100644 index 00000000000..83c27ff73cb --- /dev/null +++ b/test/lib/ansible_test/_data/coverage_stub.ps1 @@ -0,0 +1,38 @@ +<# +.SYNOPSIS +Gets the lines to hit from a sourcefile for coverage stubs. +#> +[CmdletBinding()] +param ( + [Parameter(Mandatory, ValueFromRemainingArguments)] + [String[]] + $Path +) + +$stubInfo = @(foreach ($sourcePath in $Path) { + # Default is to just no lines for missing files + [Collections.Generic.HashSet[int]]$lines = @() + + if (Test-Path -LiteralPath $sourcePath) { + $code = [ScriptBlock]::Create([IO.File]::ReadAllText($sourcePath)) + + # We set our breakpoints with this predicate so our stubs should match + # that logic. + $predicate = { + $args[0] -is [System.Management.Automation.Language.CommandBaseAst] + } + $cmds = $code.Ast.FindAll($predicate, $true) + + # We only care about unique lines not multiple commands on 1 line. + $lines = @(foreach ($cmd in $cmds) { + $cmd.Extent.StartLineNumber + }) + } + + [PSCustomObject]@{ + Path = $sourcePath + Lines = $lines + } +}) + +ConvertTo-Json -InputObject $stubInfo -Depth 2 -Compress diff --git a/test/lib/ansible_test/_internal/commands/coverage/combine.py b/test/lib/ansible_test/_internal/commands/coverage/combine.py index ffc6351506d..f163dff76b6 100644 --- a/test/lib/ansible_test/_internal/commands/coverage/combine.py +++ b/test/lib/ansible_test/_internal/commands/coverage/combine.py @@ -3,6 +3,7 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type import os +import json from ...target import ( walk_compile_targets, @@ -14,11 +15,14 @@ from ...io import ( ) from ...util import ( + ANSIBLE_TEST_DATA_ROOT, display, + find_executable, ) from ...util_common import ( ResultType, + run_command, write_json_file, write_json_test_results, ) @@ -64,7 +68,7 @@ def _command_coverage_combine_python(args): counter = 0 sources = _get_coverage_targets(args, walk_compile_targets) - groups = _build_stub_groups(args, sources, lambda line_count: set()) + groups = _build_stub_groups(args, sources, lambda s: dict((name, set()) for name in s)) collection_search_re, collection_sub_re = get_collection_path_regexes() @@ -137,11 +141,13 @@ def _command_coverage_combine_powershell(args): """ coverage_files = get_powershell_coverage_files() - def _default_stub_value(lines): - val = {} - for line in range(lines): - val[line] = 0 - return val + def _default_stub_value(source_paths): + cmd = ['pwsh', os.path.join(ANSIBLE_TEST_DATA_ROOT, 'coverage_stub.ps1')] + cmd.extend(source_paths) + + stubs = json.loads(run_command(args, cmd, capture=True, always=True)[0]) + + return dict((d['Path'], dict((line, 0) for line in d['Lines'])) for d in stubs) counter = 0 sources = _get_coverage_targets(args, walk_powershell_targets) @@ -236,7 +242,7 @@ def _build_stub_groups(args, sources, default_stub_value): """ :type args: CoverageConfig :type sources: List[tuple[str, int]] - :type default_stub_value: Func[int] + :type default_stub_value: Func[List[str]] :rtype: dict """ groups = {} @@ -248,7 +254,7 @@ def _build_stub_groups(args, sources, default_stub_value): stub_line_count = 0 for source, source_line_count in sources: - stub_group.append((source, source_line_count)) + stub_group.append(source) stub_line_count += source_line_count if stub_line_count > stub_line_limit: @@ -260,8 +266,7 @@ def _build_stub_groups(args, sources, default_stub_value): if not stub_group: continue - groups['=stub-%02d' % (stub_index + 1)] = dict((source, default_stub_value(line_count)) - for source, line_count in stub_group) + groups['=stub-%02d' % (stub_index + 1)] = default_stub_value(stub_group) return groups