diff --git a/t/meson.build b/t/meson.build index a5531df415..551c3036c0 100644 --- a/t/meson.build +++ b/t/meson.build @@ -131,6 +131,7 @@ integration_tests = [ 't0210-trace2-normal.sh', 't0211-trace2-perf.sh', 't0212-trace2-event.sh', + 't0213-trace2-ancestry.sh', 't0300-credentials.sh', 't0301-credential-cache.sh', 't0302-credential-store.sh', diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh index 96c68f65df..7e1e7af862 100755 --- a/t/t0210-trace2-normal.sh +++ b/t/t0210-trace2-normal.sh @@ -74,8 +74,9 @@ scrub_normal () { # This line is only emitted when RUNTIME_PREFIX is defined, # so just omit it for testing purposes. # - # 4. 'cmd_ancestry' is not implemented everywhere, so for portability's - # sake, skip it when parsing normal. + # 4. 'cmd_ancestry' output depends on how the test is run and + # is not relevant to the features we are testing here. + # Ancestry tests are covered in t0213-trace2-ancestry.sh instead. sed \ -e 's/elapsed:[0-9]*\.[0-9][0-9]*\([eE][-+]\{0,1\}[0-9][0-9]*\)\{0,1\}/elapsed:_TIME_/g' \ -e "s/^start '[^']*' \(.*\)/start _EXE_ \1/" \ diff --git a/t/t0213-trace2-ancestry.sh b/t/t0213-trace2-ancestry.sh new file mode 100755 index 0000000000..a2b9536da8 --- /dev/null +++ b/t/t0213-trace2-ancestry.sh @@ -0,0 +1,180 @@ +#!/bin/sh + +test_description='test trace2 cmd_ancestry event' + +. ./test-lib.sh + +# Turn off any inherited trace2 settings for this test. +sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT +sane_unset GIT_TRACE2_BRIEF +sane_unset GIT_TRACE2_CONFIG_PARAMS + +# Add t/helper directory to PATH so that we can use a relative +# path to run nested instances of test-tool.exe (see 004child). +# This helps with HEREDOC comparisons later. +TTDIR="$GIT_BUILD_DIR/t/helper/" && export TTDIR +PATH="$TTDIR:$PATH" && export PATH + +# The 400ancestry helper spawns a child process so that the child +# sees "test-tool" in its process ancestry. We capture only the +# child's trace2 output to a file. +# +# The tests use git commands that spawn child git processes (e.g., +# alias resolution) to create a controlled multi-level process tree. +# Because cmd_ancestry walks the real process tree, processes will +# also report ancestors above "test-tool" that depend on the test +# runner environment (e.g., bash, make, tmux). The filter functions +# below truncate the ancestry at "test-tool", discarding anything +# above it, so only the controlled portion is verified. +# +# On platforms without a real procinfo implementation (the stub), +# no cmd_ancestry event is emitted. We detect this at runtime and +# skip the format-specific tests accordingly. + +# Determine if cmd_ancestry is supported on this platform. +test_expect_success 'detect cmd_ancestry support' ' + test_when_finished "rm -f trace.detect" && + GIT_TRACE2_BRIEF=1 GIT_TRACE2="$(pwd)/trace.detect" \ + test-tool trace2 001return 0 && + if grep -q "^cmd_ancestry" trace.detect + then + test_set_prereq TRACE2_ANCESTRY + fi +' + +# Filter functions for each trace2 target format. +# +# Each extracts cmd_ancestry events, strips format-specific syntax, +# and truncates the ancestor list at the outermost "test-tool" +# (or "test-tool.exe" on Windows), discarding any higher-level +# (uncontrolled) ancestors. +# +# Output is a space-separated list of ancestor names, one line per +# cmd_ancestry event, with the immediate parent listed first: +# +# test-tool (or: test-tool.exe) +# git test-tool (or: git.exe test-tool.exe) +# git test-tool test-tool (or: git.exe test-tool.exe test-tool.exe) + +if test_have_prereq MINGW +then + TT=test-tool$X +else + TT=test-tool +fi + +filter_ancestry_normal () { + sed -n '/^cmd_ancestry/{ + s/^cmd_ancestry // + s/ <- / /g + s/\(.*'"$TT"'\) .*/\1/ + p + }' +} + +filter_ancestry_perf () { + sed -n '/cmd_ancestry/{ + s/.*ancestry:\[// + s/\]// + s/\(.*'"$TT"'\) .*/\1/ + p + }' +} + +filter_ancestry_event () { + sed -n '/"cmd_ancestry"/{ + s/.*"ancestry":\[// + s/\].*// + s/"//g + s/,/ /g + s/\(.*'"$TT"'\) .*/\1/ + p + }' +} + +# On Windows (MINGW) when running with the bin-wrappers, we also see "sh.exe" in +# the ancestry. We must therefore account for this expected ancestry element in +# the expected output of the tests. +if test_have_prereq MINGW && test -z "$no_bin_wrappers"; then + SH_TT="sh$X $TT" +else + SH_TT="$TT" +fi + +# Git alias resolution spawns the target command as a child process. +# Using "git -c alias.xyz=version xyz" creates a two-level chain: +# +# test-tool (400ancestry) +# -> git (resolves alias xyz -> version) +# -> git (version) +# +# Both git processes are instrumented and emit cmd_ancestry. After +# filtering out ancestors above test-tool, we get: +# +# test-tool (from git alias resolver) +# git test-tool (from git version) + +test_expect_success TRACE2_ANCESTRY 'normal: git alias chain, 2 levels' ' + test_when_finished "rm -f trace.normal actual expect" && + test-tool trace2 400ancestry normal "$(pwd)/trace.normal" \ + git -c alias.xyz=version xyz && + filter_ancestry_normal actual && + cat >expect <<-EOF && + $SH_TT + git$X $SH_TT + EOF + test_cmp expect actual +' + +test_expect_success TRACE2_ANCESTRY 'perf: git alias chain, 2 levels' ' + test_when_finished "rm -f trace.perf actual expect" && + test-tool trace2 400ancestry perf "$(pwd)/trace.perf" \ + git -c alias.xyz=version xyz && + filter_ancestry_perf actual && + cat >expect <<-EOF && + $SH_TT + git$X $SH_TT + EOF + test_cmp expect actual +' + +test_expect_success TRACE2_ANCESTRY 'event: git alias chain, 2 levels' ' + test_when_finished "rm -f trace.event actual expect" && + test-tool trace2 400ancestry event "$(pwd)/trace.event" \ + git -c alias.xyz=version xyz && + filter_ancestry_event actual && + cat >expect <<-EOF && + $SH_TT + git$X $SH_TT + EOF + test_cmp expect actual +' + +# Use 004child to add a test-tool layer, creating a three-level chain: +# +# test-tool (400ancestry) +# -> test-tool (004child) +# -> git (resolves alias xyz -> version) +# -> git (version) +# +# Three instrumented processes emit cmd_ancestry. After filtering: +# +# test-tool (from test-tool 004child) +# test-tool test-tool (from git alias resolver) +# git test-tool test-tool (from git version) + +test_expect_success TRACE2_ANCESTRY 'normal: deeper chain, 3 levels' ' + test_when_finished "rm -f trace.normal actual expect" && + test-tool trace2 400ancestry normal "$(pwd)/trace.normal" \ + test-tool trace2 004child \ + git -c alias.xyz=version xyz && + filter_ancestry_normal actual && + cat >expect <<-EOF && + $TT + $SH_TT $TT + git$X $SH_TT $TT + EOF + test_cmp expect actual +' + +test_done