mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-18 00:58:30 +09:00
[Fix] (CI): make split controls mandatory and isolate runner evidence
This commit is contained in:
+19
-21
@@ -962,6 +962,8 @@ jobs:
|
|||||||
# workflow passed that option. They had never been compiled by CI, let alone run.
|
# workflow passed that option. They had never been compiled by CI, let alone run.
|
||||||
- name: Unit tests on the split runtime
|
- name: Unit tests on the split runtime
|
||||||
working-directory: build-split
|
working-directory: build-split
|
||||||
|
env:
|
||||||
|
MOBILEGL_ITEST_REQUIRE_GPU: "1"
|
||||||
run: ctest --output-on-failure -L unit --no-tests=error -j "$(nproc)"
|
run: ctest --output-on-failure -L unit --no-tests=error -j "$(nproc)"
|
||||||
|
|
||||||
# --no-tests=error is half the gate, exactly as in integration-verify: the integration-split
|
# --no-tests=error is half the gate, exactly as in integration-verify: the integration-split
|
||||||
@@ -979,13 +981,11 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
ulimit -c unlimited
|
ulimit -c unlimited
|
||||||
sudo sysctl -w kernel.core_pattern='/tmp/core.%e.%p'
|
sudo sysctl -w kernel.core_pattern='/tmp/core.%e.%p'
|
||||||
ctest --output-on-failure -L integration-split --no-tests=error -j 4
|
ctest --output-on-failure -L integration-split --no-tests=error -j 4 --output-junit "${RUNNER_TEMP}/split-baseline.xml"
|
||||||
|
python3 ../scripts/ci/junit_tally.py "${RUNNER_TEMP}/split-baseline.xml" --require-split-ran
|
||||||
|
|
||||||
# ARCHITECTURE.md:521 asks for `ctest -L integration-gpu` to be name-for-name identical
|
# ID-65 supersedes broad inproc status parity: class-C aborts and named wrong-answer
|
||||||
# between the monolith and the split arm of the SAME build - the G2 shape extended to a
|
# debts are recorded. Monolith, integration-split and the controls remain hard gates.
|
||||||
# third arm. The knob goes in the JOB environment rather than in a ctest property, for the
|
|
||||||
# reason the MOBILEGL_ESPRYT_DISABLE_INVALIDATE_FLUSH precedent in `integration` gives: a
|
|
||||||
# property would override it and the arm would not be an arm.
|
|
||||||
#
|
#
|
||||||
# The entries that name MOBILEGL_TRANSPORT in their OWN property (the Split. lanes) keep
|
# The entries that name MOBILEGL_TRANSPORT in their OWN property (the Split. lanes) keep
|
||||||
# their value in both passes, which is correct: they are the split family in both arms and
|
# their value in both passes, which is correct: they are the split family in both arms and
|
||||||
@@ -1007,14 +1007,11 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
echo "integration-gpu entries in the split build: ${count}"
|
echo "integration-gpu entries in the split build: ${count}"
|
||||||
MOBILEGL_TRANSPORT=monolith ctest --output-on-failure -L integration-gpu --no-tests=error -j 4 --output-junit "${RUNNER_TEMP}/arm-monolith.xml"
|
MOBILEGL_TRANSPORT=monolith ctest --output-on-failure -L integration-gpu --no-tests=error -j 4 --output-junit "${RUNNER_TEMP}/arm-monolith.xml"
|
||||||
MOBILEGL_TRANSPORT=inproc ctest --output-on-failure -L integration-gpu --no-tests=error -j 4 --output-junit "${RUNNER_TEMP}/arm-inproc.xml"
|
# ID-65: broad inproc is a recorded debt census. Reduced split + controls gate below.
|
||||||
# NAME **AND STATUS**, and it is the comparison this step claimed to make and did not
|
inproc_rc=0
|
||||||
# (review finding N-3): the first version wrote a names file and never read it, and
|
MOBILEGL_TRANSPORT=inproc ctest --output-on-failure -L integration-gpu --no-tests=error -j 4 --output-junit "${RUNNER_TEMP}/arm-inproc.xml" || inproc_rc=$?
|
||||||
# `--output-on-failure` treats a SKIPPED test as not-a-failure - so the very failure
|
python3 ../scripts/ci/census_junit.py "${RUNNER_TEMP}/arm-inproc.xml" "${inproc_rc}" >> "${GITHUB_STEP_SUMMARY}"
|
||||||
# ARCHITECTURE.md:521 is about, "an inproc arm that skipped forty entries the monolith arm
|
# Retain the per-name status delta as evidence, not as the reduced-path gate.
|
||||||
# ran", was invisible here and caught only by the local gate. `ctest -N` cannot see it
|
|
||||||
# either: this is one build directory, so the two arms have identical name lists by
|
|
||||||
# construction and the difference is entirely in what each entry DID.
|
|
||||||
python3 - "${RUNNER_TEMP}/arm-monolith.xml" "${RUNNER_TEMP}/arm-inproc.xml" <<'PY'
|
python3 - "${RUNNER_TEMP}/arm-monolith.xml" "${RUNNER_TEMP}/arm-inproc.xml" <<'PY'
|
||||||
import sys, xml.etree.ElementTree as ET
|
import sys, xml.etree.ElementTree as ET
|
||||||
def rows(path):
|
def rows(path):
|
||||||
@@ -1031,13 +1028,10 @@ jobs:
|
|||||||
diff = sorted(set(a) ^ set(b)) + sorted(n for n in set(a) & set(b) if a[n] != b[n])
|
diff = sorted(set(a) ^ set(b)) + sorted(n for n in set(a) & set(b) if a[n] != b[n])
|
||||||
if diff:
|
if diff:
|
||||||
for name in diff[:40]:
|
for name in diff[:40]:
|
||||||
print(f"::error::{name}: monolith={a.get(name, '<absent>')} inproc={b.get(name, '<absent>')}")
|
print(f"{name}: monolith={a.get(name, '<absent>')} inproc={b.get(name, '<absent>')}")
|
||||||
print(f"::error::the monolith and inproc arms of ctest -L integration-gpu differ on "
|
print(f"Recorded ID-65 census: {len(diff)} name/status differences; not a parity gate")
|
||||||
f"{len(diff)} entries. ARCHITECTURE.md:521 requires them identical name for name "
|
else:
|
||||||
f"AND status; an entry that SKIPPED on one arm and ran on the other is the "
|
print(f"the two arms agree on all {len(a)} entries, name and status")
|
||||||
f"failure this compares for, and it is not a failure to --output-on-failure.")
|
|
||||||
raise SystemExit(1)
|
|
||||||
print(f"the two arms agree on all {len(a)} entries, name and status")
|
|
||||||
PY
|
PY
|
||||||
|
|
||||||
# THE RUNTIME HALF OF "THIS IS REALLY A SPLIT BUILD". The build-level nm check in
|
# THE RUNTIME HALF OF "THIS IS REALLY A SPLIT BUILD". The build-level nm check in
|
||||||
@@ -1095,6 +1089,7 @@ jobs:
|
|||||||
# and FAILED as evidence the lane was live, so the controls could be measured against a
|
# and FAILED as evidence the lane was live, so the controls could be measured against a
|
||||||
# baseline that was already red.
|
# baseline that was already red.
|
||||||
- name: Negative controls - the verb barrier and the persistent-map push must be load-bearing
|
- name: Negative controls - the verb barrier and the persistent-map push must be load-bearing
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
working-directory: build-split
|
working-directory: build-split
|
||||||
env:
|
env:
|
||||||
MOBILEGL_ITEST_REQUIRE_GPU: "1"
|
MOBILEGL_ITEST_REQUIRE_GPU: "1"
|
||||||
@@ -1109,6 +1104,8 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
build-split/MobileGL/MG_IntegrationTest/*.log*
|
build-split/MobileGL/MG_IntegrationTest/*.log*
|
||||||
build-split/MobileGL/MG_IntegrationTest/split-logs/*.log
|
build-split/MobileGL/MG_IntegrationTest/split-logs/*.log
|
||||||
|
${{ runner.temp }}/arm-inproc.xml
|
||||||
|
${{ runner.temp }}/arm-monolith.xml
|
||||||
if-no-files-found: warn
|
if-no-files-found: warn
|
||||||
|
|
||||||
- name: Upload core dumps
|
- name: Upload core dumps
|
||||||
@@ -1978,6 +1975,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CONTROL_TMPDIR: ${{ runner.temp }}
|
CONTROL_TMPDIR: ${{ runner.temp }}
|
||||||
LIBRARY_LOG: ${{ matrix.case }}/${{ matrix.backend }}/output/mobilegl.log
|
LIBRARY_LOG: ${{ matrix.case }}/${{ matrix.backend }}/output/mobilegl.log
|
||||||
|
FROZEN_LIBRARY: ${{ github.workspace }}/build-linux/libMobileGL.so
|
||||||
run: >-
|
run: >-
|
||||||
bash "${GITHUB_WORKSPACE}/scripts/ci/retrace_drop_draw_control.sh"
|
bash "${GITHUB_WORKSPACE}/scripts/ci/retrace_drop_draw_control.sh"
|
||||||
'${{ matrix.case }}' '${{ matrix.backend }}'
|
'${{ matrix.case }}' '${{ matrix.backend }}'
|
||||||
|
|||||||
@@ -68,6 +68,14 @@ def main():
|
|||||||
for n in selected for c in by_name[n])
|
for n in selected for c in by_name[n])
|
||||||
if not_failed:
|
if not_failed:
|
||||||
raise ValueError(f"{label} control: {not_failed} selected entries did not fail")
|
raise ValueError(f"{label} control: {not_failed} selected entries did not fail")
|
||||||
|
elif mode == "assertion":
|
||||||
|
cases = ET.parse(sys.argv[4]).getroot().findall(".//testcase")
|
||||||
|
by_name = {case.get("name"): case for case in cases}
|
||||||
|
for name in selected:
|
||||||
|
case = by_name.get(name)
|
||||||
|
output = "" if case is None else " ".join(" ".join(case.itertext()).split())
|
||||||
|
if not re.search(sys.argv[5], output):
|
||||||
|
raise ValueError(f"E3(a) FAILED: {name} red lacks its persistent-map push diagnostic")
|
||||||
elif mode == "evidence":
|
elif mode == "evidence":
|
||||||
missing = []
|
missing = []
|
||||||
label = sys.argv[5] if len(sys.argv) > 5 else ""
|
label = sys.argv[5] if len(sys.argv) > 5 else ""
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ def cases():
|
|||||||
[SUITE+'BoundPackBufferOffsetReadRefusesByName'], 'RemoteClientTest'),
|
[SUITE+'BoundPackBufferOffsetReadRefusesByName'], 'RemoteClientTest'),
|
||||||
('codex12-repeat-skip', BACKEND,
|
('codex12-repeat-skip', BACKEND,
|
||||||
replace('if (draw != EGL_NO_SURFACE && ctx != EGL_NO_CONTEXT) {', 'if (false) {'),
|
replace('if (draw != EGL_NO_SURFACE && ctx != EGL_NO_CONTEXT) {', 'if (false) {'),
|
||||||
[SUITE+'RepeatedMakeCurrentAdoptsRepublishedCapsWithoutAPumpOrPresent'], 'RemoteClientTest'),
|
[SUITE+'ADifferentTupleMakeCurrentIsAdoptedWithoutAPumpOrPresent'], 'RemoteClientTest'),
|
||||||
('BlobMissing-optional-to-required', WIRE,
|
('BlobMissing-optional-to-required', WIRE,
|
||||||
replace('record.Blob = StageOptional(session, blobBytes, blobByteCount);',
|
replace('record.Blob = StageOptional(session, blobBytes, blobByteCount);',
|
||||||
'record.Blob = StageRequired(session, "SetDynamicState", blobBytes, blobByteCount);'),
|
'record.Blob = StageRequired(session, "SetDynamicState", blobBytes, blobByteCount);'),
|
||||||
@@ -122,13 +122,20 @@ def main():
|
|||||||
binary = ROOT / 'build-split/MobileGL/MG_Test' / ('Pipe' if target == 'PipeCatalogueTest' else 'Wire') / target
|
binary = ROOT / 'build-split/MobileGL/MG_Test' / ('Pipe' if target == 'PipeCatalogueTest' else 'Wire') / target
|
||||||
build = ['cmake', '--build', 'build-split', '-j', '24', '--target', target]
|
build = ['cmake', '--build', 'build-split', '-j', '24', '--target', target]
|
||||||
run = [str(binary), '--gtest_filter='+':'.join(names)]
|
run = [str(binary), '--gtest_filter='+':'.join(names)]
|
||||||
|
# ID-67: both replacement cases must execute green before/after this mutation.
|
||||||
|
# Suppressing client adoption only reddens the different-tuple case; an identical
|
||||||
|
# tuple correctly republishes nothing and must remain green under the perturbation.
|
||||||
|
green_names = names
|
||||||
|
if label == 'codex12-repeat-skip':
|
||||||
|
green_names = names + [SUITE+'AnIdenticalRepeatedMakeCurrentRepublishesNothing']
|
||||||
|
green_run = [str(binary), '--gtest_filter='+':'.join(green_names)]
|
||||||
print('\n=== '+label+' ===', flush=True)
|
print('\n=== '+label+' ===', flush=True)
|
||||||
try:
|
try:
|
||||||
brc, out = command(build)
|
brc, out = command(build)
|
||||||
if brc:
|
if brc:
|
||||||
raise RuntimeError('baseline build failed\n'+out)
|
raise RuntimeError('baseline build failed\n'+out)
|
||||||
rc, out = command(run)
|
rc, out = command(green_run)
|
||||||
if rc or any('[ OK ] '+name+' (' not in out for name in names):
|
if rc or any('[ OK ] '+name+' (' not in out for name in green_names):
|
||||||
raise RuntimeError('baseline not green\n'+out)
|
raise RuntimeError('baseline not green\n'+out)
|
||||||
path.write_text(mutate(original.decode()))
|
path.write_text(mutate(original.decode()))
|
||||||
brc, out = command(build)
|
brc, out = command(build)
|
||||||
@@ -146,12 +153,12 @@ def main():
|
|||||||
finally:
|
finally:
|
||||||
path.write_bytes(original)
|
path.write_bytes(original)
|
||||||
brc, out = command(build)
|
brc, out = command(build)
|
||||||
rc, out = command(run) if brc == 0 else (brc, out)
|
rc, out = command(green_run) if brc == 0 else (brc, out)
|
||||||
if rc or any('[ OK ] '+name+' (' not in out for name in names):
|
if rc or any('[ OK ] '+name+' (' not in out for name in green_names):
|
||||||
print('RESTORE-FAIL\n'+out, flush=True)
|
print('RESTORE-FAIL\n'+out, flush=True)
|
||||||
failures.append(label+' restore')
|
failures.append(label+' restore')
|
||||||
else:
|
else:
|
||||||
print('RESTORED GREEN: '+', '.join(names), flush=True)
|
print('RESTORED GREEN: '+', '.join(green_names), flush=True)
|
||||||
print('FAILED_CONTROLS='+repr(failures), flush=True)
|
print('FAILED_CONTROLS='+repr(failures), flush=True)
|
||||||
return bool(failures)
|
return bool(failures)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Summarize the indebted broad lane without turning debt into a hard gate."""
|
||||||
|
import collections
|
||||||
|
import sys
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
cases = ET.parse(sys.argv[1]).getroot().findall('.//testcase')
|
||||||
|
if not cases:
|
||||||
|
sys.exit('Census FAILED: no executed test records')
|
||||||
|
counts = collections.Counter()
|
||||||
|
for case in cases:
|
||||||
|
failure = case.find('failure')
|
||||||
|
if failure is not None:
|
||||||
|
reason = failure.get('message', '')
|
||||||
|
status = 'aborted' if 'aborted' in reason.lower() else 'failed'
|
||||||
|
elif case.find('skipped') is not None:
|
||||||
|
status = 'skipped'
|
||||||
|
else:
|
||||||
|
status = 'passed'
|
||||||
|
counts[status] += 1
|
||||||
|
print('### Broad inproc census (ID-65: recorded debt, not a gate)')
|
||||||
|
print(f'CTest exit: {sys.argv[2]}; total: {len(cases)}')
|
||||||
|
print('\n| passed | skipped | aborted | failed |\n|---:|---:|---:|---:|')
|
||||||
|
print('| ' + ' | '.join(str(counts[k]) for k in ('passed', 'skipped', 'aborted', 'failed')) + ' |')
|
||||||
@@ -56,10 +56,15 @@ run_split() { # $1 = STUB_MODE
|
|||||||
run_retrace() { # $1 = STUB_MODE
|
run_retrace() { # $1 = STUB_MODE
|
||||||
cd "${WORK}" || return 127
|
cd "${WORK}" || return 127
|
||||||
mkdir -p "${WORK}/OpenRA"
|
mkdir -p "${WORK}/OpenRA"
|
||||||
|
local rc=0
|
||||||
env -i PATH="${STUB_DIR}:/usr/bin:/bin" STUB_MODE="$1" \
|
env -i PATH="${STUB_DIR}:/usr/bin:/bin" STUB_MODE="$1" \
|
||||||
CTEST=ctest CONTROL_TMPDIR="${WORK}/tmp-$1" \
|
CTEST=ctest CONTROL_TMPDIR="${WORK}/tmp-$1" \
|
||||||
PULL_LIBRARY="${WORK}/pull.so" FROZEN_LIBRARY="${WORK}/frozen.so" \
|
PULL_LIBRARY="${WORK}/pull.so" FROZEN_LIBRARY="${WORK}/frozen.so" \
|
||||||
bash "${HERE}/retrace_pull_library_control.sh" OpenRA DirectGLES
|
bash "${HERE}/retrace_pull_library_control.sh" OpenRA DirectGLES || rc=$?
|
||||||
|
cmp -s "${WORK}/frozen.so" "${WORK}/split.so" || {
|
||||||
|
echo 'F6 FAILED: pull control did not restore the split library'; return 1;
|
||||||
|
}
|
||||||
|
return "${rc}"
|
||||||
}
|
}
|
||||||
|
|
||||||
run_drop_draw() { # $1 = STUB_MODE
|
run_drop_draw() { # $1 = STUB_MODE
|
||||||
@@ -67,7 +72,7 @@ run_drop_draw() { # $1 = STUB_MODE
|
|||||||
mkdir -p "${WORK}/OpenRA"
|
mkdir -p "${WORK}/OpenRA"
|
||||||
env -i PATH="${STUB_DIR}:/usr/bin:/bin" STUB_MODE="$1" \
|
env -i PATH="${STUB_DIR}:/usr/bin:/bin" STUB_MODE="$1" \
|
||||||
CTEST=ctest CONTROL_TMPDIR="${WORK}/tmp-$1" \
|
CTEST=ctest CONTROL_TMPDIR="${WORK}/tmp-$1" \
|
||||||
LIBRARY_LOG="${WORK}/tmp-$1/mobilegl.log" \
|
FROZEN_LIBRARY="${WORK}/frozen.so" LIBRARY_LOG="${WORK}/tmp-$1/mobilegl.log" \
|
||||||
bash "${HERE}/retrace_drop_draw_control.sh" OpenRA DirectGLES
|
bash "${HERE}/retrace_drop_draw_control.sh" OpenRA DirectGLES
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,8 +85,8 @@ expect PASSED "the scenarios' own diagnostic" -- run_split evidenc
|
|||||||
expect FAILED "the knob leaves the selection green" -- run_split green
|
expect FAILED "the knob leaves the selection green" -- run_split green
|
||||||
# The arming counter's half of the finding: a baseline that is already red cannot arm anything.
|
# The arming counter's half of the finding: a baseline that is already red cannot arm anything.
|
||||||
expect FAILED "the baseline is already red" -- run_split red-baseline
|
expect FAILED "the baseline is already red" -- run_split red-baseline
|
||||||
# The disarmed lane, which is a legitimate exit 0 while c1/s1/v1 are landing.
|
# P5 is complete: losing the runtime implementation must no longer disarm the gate.
|
||||||
expect PASSED "every split entry skipped (lane not armed)" -- run_split all-skipped
|
expect FAILED "every split entry skipped (implementation lost)" -- run_split all-skipped
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "=== the retrace lane's pull-library control (scripts/ci/retrace_pull_library_control.sh)"
|
echo "=== the retrace lane's pull-library control (scripts/ci/retrace_pull_library_control.sh)"
|
||||||
@@ -93,7 +98,9 @@ else
|
|||||||
echo "no cc available; the retrace half of this smoke test needs one" >&2
|
echo "no cc available; the retrace half of this smoke test needs one" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
: > "${WORK}/frozen.so"
|
printf '%s\n' 'int MG_Remote_stub(void) { return 1; }' > "${WORK}/split.c"
|
||||||
|
cc -shared -fPIC -o "${WORK}/frozen.so" "${WORK}/split.c" || exit 1
|
||||||
|
cp "${WORK}/frozen.so" "${WORK}/split.so"
|
||||||
|
|
||||||
# THE FINDING, part (b): a regex matching no tests. --no-tests=error exits non-zero and the old
|
# THE FINDING, part (b): a regex matching no tests. --no-tests=error exits non-zero and the old
|
||||||
# control read that as "the pull library turned it red".
|
# control read that as "the pull library turned it red".
|
||||||
|
|||||||
@@ -20,9 +20,11 @@ import sys
|
|||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
def tally(path):
|
def tally(path, split_only=False):
|
||||||
passed = failed = skipped = 0
|
passed = failed = skipped = 0
|
||||||
for case in ET.parse(path).getroot().iter('testcase'):
|
for case in ET.parse(path).getroot().iter('testcase'):
|
||||||
|
if split_only and not case.get('name', '').startswith('DirectGLES.Split.'):
|
||||||
|
continue
|
||||||
if case.find('failure') is not None or case.find('error') is not None:
|
if case.find('failure') is not None or case.find('error') is not None:
|
||||||
failed += 1
|
failed += 1
|
||||||
elif case.find('skipped') is not None or case.get('status') in ('notrun', 'disabled'):
|
elif case.find('skipped') is not None or case.get('status') in ('notrun', 'disabled'):
|
||||||
@@ -33,15 +35,18 @@ def tally(path):
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) not in (2, 3) or (len(sys.argv) == 3 and sys.argv[2] != '--require-split-ran'):
|
||||||
print("usage: junit_tally.py <junit.xml>", file=sys.stderr)
|
print("usage: junit_tally.py <junit.xml> [--require-split-ran]", file=sys.stderr)
|
||||||
return 2
|
return 2
|
||||||
try:
|
try:
|
||||||
passed, failed, skipped = tally(sys.argv[1])
|
passed, failed, skipped = tally(sys.argv[1], split_only=len(sys.argv) == 3)
|
||||||
except Exception as exc: # a malformed file is not "zero of everything"
|
except Exception as exc: # a malformed file is not "zero of everything"
|
||||||
print(f"junit_tally: cannot parse {sys.argv[1]}: {exc}", file=sys.stderr)
|
print(f"junit_tally: cannot parse {sys.argv[1]}: {exc}", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
print(f"{passed} {failed} {skipped}")
|
print(f"{passed} {failed} {skipped}")
|
||||||
|
if len(sys.argv) == 3 and (passed == 0 or failed):
|
||||||
|
print('split baseline FAILED: no successful split runtime entries or an already-red selection', file=sys.stderr)
|
||||||
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ split, retrace, dropdraw = sys.argv[1], sys.argv[2], sys.argv[3]
|
|||||||
# other two catching the smoke test's "unrelated failure" case, and the case never flips - which
|
# other two catching the smoke test's "unrelated failure" case, and the case never flips - which
|
||||||
# is what this script measured the first time the perturbation actually applied.
|
# is what this script measured the first time the perturbation actually applied.
|
||||||
rules = [
|
rules = [
|
||||||
(split, [('LINE', 'grep -qE "${evidence}"', ('if ! ', 'elif ! ')),
|
(split, [('LINE', '"${log_helper}" assertion', ('if ! ', 'elif ! ')),
|
||||||
('SUBST', '"[A-Za-z_][A-Za-z_0-9]*"\\}\' || exit 1', '"[A-Za-z_][A-Za-z_0-9]*"\\}\' || true'),
|
('SUBST', '"[A-Za-z_][A-Za-z_0-9]*"\\}\' || exit 1', '"[A-Za-z_][A-Za-z_0-9]*"\\}\' || true'),
|
||||||
('SUBST', '"${private_evidence}" "${name}" || exit 1',
|
('SUBST', '"${private_evidence}" "${name}" || exit 1',
|
||||||
'"${private_evidence}" "${name}" || true')]),
|
'"${private_evidence}" "${name}" || true')]),
|
||||||
|
|||||||
@@ -50,6 +50,14 @@ CTEST="${CTEST:-ctest}"
|
|||||||
CONTROL_TMPDIR="${CONTROL_TMPDIR:-${RUNNER_TEMP:-/tmp}}"
|
CONTROL_TMPDIR="${CONTROL_TMPDIR:-${RUNNER_TEMP:-/tmp}}"
|
||||||
LIBRARY_LOG="${LIBRARY_LOG:-${CASE}/${BACKEND}/output/mobilegl.log}"
|
LIBRARY_LOG="${LIBRARY_LOG:-${CASE}/${BACKEND}/output/mobilegl.log}"
|
||||||
mkdir -p "${CONTROL_TMPDIR}"
|
mkdir -p "${CONTROL_TMPDIR}"
|
||||||
|
FROZEN_LIBRARY="${FROZEN_LIBRARY:?FROZEN_LIBRARY must name the split library the replay loads}"
|
||||||
|
symbols=$(nm --defined-only "${FROZEN_LIBRARY}") || exit 1
|
||||||
|
remote_count=$(printf '%s\n' "${symbols}" | grep -ic MG_Remote || true)
|
||||||
|
echo "draw-drop control library: ${FROZEN_LIBRARY}: MG_Remote=${remote_count}"
|
||||||
|
if [ "${remote_count}" -lt 1 ]; then
|
||||||
|
echo '::error::draw-drop control requires a split library: MG_Remote=0'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
selector="^MobileGLTraceReplay\.${CASE}\.${BACKEND}$"
|
selector="^MobileGLTraceReplay\.${CASE}\.${BACKEND}$"
|
||||||
|
|
||||||
@@ -66,6 +74,8 @@ restore_good_output() {
|
|||||||
echo "restored the verified run's output over the control's"
|
echo "restored the verified run's output over the control's"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
trap restore_good_output EXIT
|
||||||
|
trap 'exit 130' INT TERM
|
||||||
|
|
||||||
matched=$("${CTEST}" -N -R "${selector}" | grep -cE '^ *Test *#[0-9]+:')
|
matched=$("${CTEST}" -N -R "${selector}" | grep -cE '^ *Test *#[0-9]+:')
|
||||||
if [ "${matched}" -lt 1 ]; then
|
if [ "${matched}" -lt 1 ]; then
|
||||||
|
|||||||
@@ -69,6 +69,18 @@ restore_good_output() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Restore the exact split library on success, failure, and interruption. The following
|
||||||
|
# draw-drop control uses this same frozen path.
|
||||||
|
saved_library=$(mktemp "${CONTROL_TMPDIR}/split-library.XXXXXX") || exit 1
|
||||||
|
cp -p "${FROZEN_LIBRARY}" "${saved_library}" || exit 1
|
||||||
|
restore_control() {
|
||||||
|
cp -p "${saved_library}" "${FROZEN_LIBRARY}"
|
||||||
|
rm -f "${saved_library}"
|
||||||
|
restore_good_output
|
||||||
|
}
|
||||||
|
trap restore_control EXIT
|
||||||
|
trap 'exit 130' INT TERM
|
||||||
|
|
||||||
# HOLE 1: COUNT THE SELECTION FIRST. `--no-tests=error` turns an empty selection into a non-zero
|
# HOLE 1: COUNT THE SELECTION FIRST. `--no-tests=error` turns an empty selection into a non-zero
|
||||||
# exit, which is indistinguishable from a working control unless the selection is counted.
|
# exit, which is indistinguishable from a working control unless the selection is counted.
|
||||||
matched=$("${CTEST}" -N -R "${selector}" | grep -cE '^ *Test *#[0-9]+:')
|
matched=$("${CTEST}" -N -R "${selector}" | grep -cE '^ *Test *#[0-9]+:')
|
||||||
@@ -82,8 +94,11 @@ fi
|
|||||||
# in. It defines no MG_Remote symbol, so ConfigLoader has no transport parser and
|
# in. It defines no MG_Remote symbol, so ConfigLoader has no transport parser and
|
||||||
# MOBILEGL_TRANSPORT=inproc is accepted and ignored - the exact shape of "the split lane ran
|
# MOBILEGL_TRANSPORT=inproc is accepted and ignored - the exact shape of "the split lane ran
|
||||||
# monolith".
|
# monolith".
|
||||||
cp "${PULL_LIBRARY}" "${FROZEN_LIBRARY}"
|
cp "${PULL_LIBRARY}" "${FROZEN_LIBRARY}" || exit 1
|
||||||
if nm --defined-only "${FROZEN_LIBRARY}" | grep -q -i MG_Remote; then
|
symbols=$(nm --defined-only "${FROZEN_LIBRARY}") || exit 1
|
||||||
|
remote_count=$(printf '%s\n' "${symbols}" | grep -ic MG_Remote || true)
|
||||||
|
echo "pull control library: ${FROZEN_LIBRARY}: MG_Remote=${remote_count}"
|
||||||
|
if [ "${remote_count}" -ne 0 ]; then
|
||||||
restore_good_output
|
restore_good_output
|
||||||
echo "::error::the control's own library defines MG_Remote symbols, so it is not a pull build and this control would prove nothing"
|
echo "::error::the control's own library defines MG_Remote symbols, so it is not a pull build and this control would prove nothing"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ CONTROL_TMPDIR="${CONTROL_TMPDIR:-${RUNNER_TEMP:-/tmp}}"
|
|||||||
mkdir -p "${CONTROL_TMPDIR}"
|
mkdir -p "${CONTROL_TMPDIR}"
|
||||||
|
|
||||||
junit="${CONTROL_TMPDIR}/isplit.xml"
|
junit="${CONTROL_TMPDIR}/isplit.xml"
|
||||||
|
rm -f "${junit}"
|
||||||
log_helper="$(dirname "$0")/../../MobileGL/MG_IntegrationTest/Harness/split_log_paths.py"
|
log_helper="$(dirname "$0")/../../MobileGL/MG_IntegrationTest/Harness/split_log_paths.py"
|
||||||
|
|
||||||
# Check ownership even while the runtime lane is disarmed and will skip.
|
# Check ownership even while the runtime lane is disarmed and will skip.
|
||||||
@@ -87,14 +88,14 @@ echo "split entries - passed: ${baseline_passed}, failed: ${baseline_failed}, sk
|
|||||||
# A RED BASELINE DISARMS THE CONTROLS RATHER THAN ARMING THEM (review finding 8, second half).
|
# A RED BASELINE DISARMS THE CONTROLS RATHER THAN ARMING THEM (review finding 8, second half).
|
||||||
# `|| true` plus a "not skipped" counter used to treat a case that ran and FAILED as evidence the
|
# `|| true` plus a "not skipped" counter used to treat a case that ran and FAILED as evidence the
|
||||||
# lane was live. Turning an already-red entry red is not a measurement.
|
# lane was live. Turning an already-red entry red is not a measurement.
|
||||||
if [ "${baseline_failed}" -gt 0 ]; then
|
if [ "${baseline_failed}" -gt 0 ] || [ "${baseline_rc}" -ne 0 ]; then
|
||||||
echo "::error::${baseline_failed} DirectGLES.Split. entries are ALREADY RED with both knobs at their defaults, so neither negative control below can attribute its red to the knob it turns. Fix the lane first; a control measured against a red baseline is not a control. (This used to be swallowed by an unconditional '|| true' and counted as 'the lane is armed'.)"
|
echo "::error::${baseline_failed} DirectGLES.Split. entries are ALREADY RED with both knobs at their defaults, so neither negative control below can attribute its red to the knob it turns. Fix the lane first; a control measured against a red baseline is not a control. (This used to be swallowed by an unconditional '|| true' and counted as 'the lane is armed'.)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${baseline_passed}" -lt 1 ]; then
|
if [ "${baseline_passed}" -lt 1 ]; then
|
||||||
echo "::warning::every DirectGLES.Split. entry SKIPPED, so neither negative control can fire. The arming condition is a runtime fact - MG_Config::Transport, ClientSession::Active() and ImplementedVerbCount(), read by Harness/SplitRuntimePeek - and it becomes true on the commit that lands the last of c1/s1/v1. This step becomes a gate then, with no edit; it is not a green that asserted anything today."
|
echo "::error::split baseline FAILED: every DirectGLES.Split. entry SKIPPED; the split implementation did not execute"
|
||||||
exit 0
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ---- the controls ---------------------------------------------------------------------------
|
# ---- the controls ---------------------------------------------------------------------------
|
||||||
@@ -145,7 +146,7 @@ run_control() {
|
|||||||
if [ "${evidence}" = "private-barrier-fatal" ]; then
|
if [ "${evidence}" = "private-barrier-fatal" ]; then
|
||||||
python3 "${log_helper}" evidence "${manifest}" "${filter}" \
|
python3 "${log_helper}" evidence "${manifest}" "${filter}" \
|
||||||
'Fatal\{BarrierViolation, "[A-Za-z_][A-Za-z_0-9]*"\}' || exit 1
|
'Fatal\{BarrierViolation, "[A-Za-z_][A-Za-z_0-9]*"\}' || exit 1
|
||||||
elif ! tr -s '[:space:]' ' ' < "${out}" | grep -qE "${evidence}"; then
|
elif ! python3 "${log_helper}" assertion "${manifest}" "${filter}" "${result}" "${evidence}"; then
|
||||||
echo "::error::${name} FAILED: red lacks its persistent-map push diagnostic. Required: ${evidence}"
|
echo "::error::${name} FAILED: red lacks its persistent-map push diagnostic. Required: ${evidence}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -179,8 +180,10 @@ run_control "negative control E1 (MOBILEGL_IPC_VERB_BARRIER=0)" \
|
|||||||
# * the LIBRARY's own line in the entry's private file, saying the push was disabled by this
|
# * the LIBRARY's own line in the entry's private file, saying the push was disabled by this
|
||||||
# knob. It did not exist until ID-65 assigned it (joint-v1.md 3), which is why this control
|
# knob. It did not exist until ID-65 assigned it (joint-v1.md 3), which is why this control
|
||||||
# used to rest on the pixels alone.
|
# used to rest on the pixels alone.
|
||||||
|
# TheMapLandsInTheArmItsLaneDeclares skips by design outside PersistentMapArm.
|
||||||
|
# Select only the pixel cases; a pre-flight skip in either remains a hard failure.
|
||||||
run_control "negative control E3(a) (MOBILEGL_IPC_PERSISTENT_BLOCK_KB=0)" \
|
run_control "negative control E3(a) (MOBILEGL_IPC_PERSISTENT_BLOCK_KB=0)" \
|
||||||
'DirectGLES\.Split\.(SmallRing\.)?PersistentCoherentMapScenario' \
|
'DirectGLES\.Split\.(SmallRing\.)?PersistentCoherentMapScenario\.(TwoWritesThroughTheCoherentPointerEachReachTheirOwnDraw|AWriteAfterAFrameBoundaryReachesTheNextFramesDraw)$' \
|
||||||
"the SECOND write through the same mapping, announced by nothing|frame 1's write through the SAME mapping, after a Present" \
|
"the SECOND write through the same mapping, announced by nothing|frame 1's write through the SAME mapping, after a Present" \
|
||||||
'MGPipe: persistent-map push disabled - MOBILEGL_IPC_PERSISTENT_BLOCK_KB=0' \
|
'MGPipe: persistent-map push disabled - MOBILEGL_IPC_PERSISTENT_BLOCK_KB=0' \
|
||||||
MOBILEGL_IPC_PERSISTENT_BLOCK_KB=0
|
MOBILEGL_IPC_PERSISTENT_BLOCK_KB=0
|
||||||
|
|||||||
+2
-1
@@ -7,7 +7,7 @@ trap 'rm -rf "${WORK}"' EXIT
|
|||||||
cp "${HERE}/testdata/stub_ctest.sh" "${WORK}/ctest"
|
cp "${HERE}/testdata/stub_ctest.sh" "${WORK}/ctest"
|
||||||
chmod +x "${WORK}/ctest"
|
chmod +x "${WORK}/ctest"
|
||||||
passes=0
|
passes=0
|
||||||
for mode in missing-fatal stdout-fatal stale-fatal evidence e3-unrelated e3-no-private skipped-selection notrun-selection missing-selection partial-fatal wrong-fatal; do
|
for mode in missing-fatal stdout-fatal stale-fatal evidence e3-unrelated e3-no-private skipped-selection e3-skipped-selection notrun-selection missing-selection partial-fatal wrong-fatal; do
|
||||||
mkdir -p "${WORK}/${mode}"
|
mkdir -p "${WORK}/${mode}"
|
||||||
rc=0
|
rc=0
|
||||||
STUB_MODE="${mode}" CTEST="${WORK}/ctest" CONTROL_TMPDIR="${WORK}/${mode}" \
|
STUB_MODE="${mode}" CTEST="${WORK}/ctest" CONTROL_TMPDIR="${WORK}/${mode}" \
|
||||||
@@ -25,6 +25,7 @@ for mode in missing-fatal stdout-fatal stale-fatal evidence e3-unrelated e3-no-p
|
|||||||
case "${mode}" in
|
case "${mode}" in
|
||||||
e3-no-private) message='no selected private log carries /MGPipe: persistent-map push disabled' ;;
|
e3-no-private) message='no selected private log carries /MGPipe: persistent-map push disabled' ;;
|
||||||
skipped-selection) message='SplitLogPaths FAILED: E1 control: the knob killed the pre-flight, not the entry - 1 selected entries skipped' ;;
|
skipped-selection) message='SplitLogPaths FAILED: E1 control: the knob killed the pre-flight, not the entry - 1 selected entries skipped' ;;
|
||||||
|
e3-skipped-selection) message='SplitLogPaths FAILED: E3(a) control: the knob killed the pre-flight, not the entry - 1 selected entries skipped' ;;
|
||||||
notrun-selection|missing-selection) message='SplitLogPaths FAILED: E1 control: 1 selected entries did not run' ;;
|
notrun-selection|missing-selection) message='SplitLogPaths FAILED: E1 control: 1 selected entries did not run' ;;
|
||||||
esac
|
esac
|
||||||
if [[ "${mode}" = *-selection ]]; then
|
if [[ "${mode}" = *-selection ]]; then
|
||||||
|
|||||||
Vendored
+19
-2
@@ -24,7 +24,7 @@
|
|||||||
# never says the push was disabled (the half ID-65 added)
|
# never says the push was disabled (the half ID-65 added)
|
||||||
# green baseline green; the control's own run PASSES (the knob is not load-bearing)
|
# green baseline green; the control's own run PASSES (the knob is not load-bearing)
|
||||||
# red-baseline the baseline itself has a failed entry
|
# red-baseline the baseline itself has a failed entry
|
||||||
# all-skipped the baseline is entirely skipped (the disarmed lane, a legitimate exit 0)
|
# all-skipped the baseline is entirely skipped (lost implementation, a hard failure)
|
||||||
# retrace-noselect `ctest -N` matches nothing; the run exits 8 the way --no-tests=error does
|
# retrace-noselect `ctest -N` matches nothing; the run exits 8 the way --no-tests=error does
|
||||||
# retrace-unrelated one match; the run fails without naming the transport
|
# retrace-unrelated one match; the run fails without naming the transport
|
||||||
# retrace-evidence one match; the run fails with run_trace_case.cmake's own sentence
|
# retrace-evidence one match; the run fails with run_trace_case.cmake's own sentence
|
||||||
@@ -76,10 +76,20 @@ write_junit() {
|
|||||||
entry=DirectGLES.Split.ClearThenReadPixelsScenario.ClearWithNoDrawIsVisibleToDefaultFramebufferReadPixels
|
entry=DirectGLES.Split.ClearThenReadPixelsScenario.ClearWithNoDrawIsVisibleToDefaultFramebufferReadPixels
|
||||||
[ "${MOBILEGL_IPC_PERSISTENT_BLOCK_KB:-64}" != 0 ] || entry=DirectGLES.Split.PersistentCoherentMapScenario.TwoWritesThroughTheCoherentPointerEachReachTheirOwnDraw
|
[ "${MOBILEGL_IPC_PERSISTENT_BLOCK_KB:-64}" != 0 ] || entry=DirectGLES.Split.PersistentCoherentMapScenario.TwoWritesThroughTheCoherentPointerEachReachTheirOwnDraw
|
||||||
body="<testcase name=\"${entry}\" status=\"fail\"><failure message=\"control red\"/></testcase>"
|
body="<testcase name=\"${entry}\" status=\"fail\"><failure message=\"control red\"/></testcase>"
|
||||||
|
if [ "${MOBILEGL_IPC_PERSISTENT_BLOCK_KB:-64}" = 0 ]; then
|
||||||
|
case "${mode}" in
|
||||||
|
evidence|e3-no-private)
|
||||||
|
body="<testcase name=\"${entry}\" status=\"fail\"><failure/><system-out>the SECOND write through the same mapping, announced by nothing</system-out></testcase>" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
if [ "${mode}" = partial-fatal ] && [ "${MOBILEGL_IPC_VERB_BARRIER:-1}" = 0 ]; then
|
if [ "${mode}" = partial-fatal ] && [ "${MOBILEGL_IPC_VERB_BARRIER:-1}" = 0 ]; then
|
||||||
body="${body}<testcase name=\"DirectGLES.Split.TriangleScenario.SecondEntry\" status=\"fail\"><failure/></testcase>"
|
body="${body}<testcase name=\"DirectGLES.Split.TriangleScenario.SecondEntry\" status=\"fail\"><failure/></testcase>"
|
||||||
fi
|
fi
|
||||||
case "${mode}" in
|
case "${mode}" in
|
||||||
|
e3-skipped-selection)
|
||||||
|
if [ "${MOBILEGL_IPC_PERSISTENT_BLOCK_KB:-64}" = 0 ]; then
|
||||||
|
body="<testcase name=\"${entry}\" status=\"notrun\"><skipped/></testcase>"
|
||||||
|
fi ;;
|
||||||
skipped-selection) body="<testcase name=\"${entry}\" status=\"notrun\"><skipped/></testcase>" ;;
|
skipped-selection) body="<testcase name=\"${entry}\" status=\"notrun\"><skipped/></testcase>" ;;
|
||||||
notrun-selection) body="<testcase name=\"${entry}\" status=\"notrun\"/>" ;;
|
notrun-selection) body="<testcase name=\"${entry}\" status=\"notrun\"/>" ;;
|
||||||
missing-selection) body='' ;;
|
missing-selection) body='' ;;
|
||||||
@@ -130,7 +140,7 @@ fi
|
|||||||
# The control's own run.
|
# The control's own run.
|
||||||
if [ "${MOBILEGL_IPC_VERB_BARRIER:-1}" = 0 ]; then
|
if [ "${MOBILEGL_IPC_VERB_BARRIER:-1}" = 0 ]; then
|
||||||
case "${mode}" in
|
case "${mode}" in
|
||||||
evidence|e3-unrelated|e3-no-private|skipped-selection|notrun-selection|missing-selection|partial-fatal) echo 'Fatal{BarrierViolation, "DrawVbo"}' > "${log}" ;;
|
evidence|e3-unrelated|e3-no-private|skipped-selection|e3-skipped-selection|notrun-selection|missing-selection|partial-fatal) echo 'Fatal{BarrierViolation, "DrawVbo"}' > "${log}" ;;
|
||||||
wrong-fatal) echo 'Fatal{ReplyMissing, "DrawVbo"}' > "${log}" ;;
|
wrong-fatal) echo 'Fatal{ReplyMissing, "DrawVbo"}' > "${log}" ;;
|
||||||
missing-fatal) echo "library setup only; no fatal" > "${log}" ;;
|
missing-fatal) echo "library setup only; no fatal" > "${log}" ;;
|
||||||
stdout-fatal) echo 'Fatal{BarrierViolation, "DrawVbo"}' ;;
|
stdout-fatal) echo 'Fatal{BarrierViolation, "DrawVbo"}' ;;
|
||||||
@@ -144,6 +154,13 @@ if [ "${MOBILEGL_IPC_PERSISTENT_BLOCK_KB:-64}" = 0 ] && [ "${mode}" = evidence ]
|
|||||||
> "${CONTROL_TMPDIR}/pmap.log"
|
> "${CONTROL_TMPDIR}/pmap.log"
|
||||||
fi
|
fi
|
||||||
case "${mode}" in
|
case "${mode}" in
|
||||||
|
e3-skipped-selection)
|
||||||
|
if [ "${MOBILEGL_IPC_PERSISTENT_BLOCK_KB:-64}" = 0 ]; then
|
||||||
|
echo 'selected E3 entry ... ***Skipped'
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
exit 8
|
||||||
|
;;
|
||||||
skipped-selection|notrun-selection|missing-selection)
|
skipped-selection|notrun-selection|missing-selection)
|
||||||
echo '1/1 Test #1: selected entry ... ***Skipped'
|
echo '1/1 Test #1: selected entry ... ***Skipped'
|
||||||
echo '100% tests passed, 0 tests failed out of 1'
|
echo '100% tests passed, 0 tests failed out of 1'
|
||||||
|
|||||||
@@ -532,7 +532,8 @@ if [ "${1:-}" = "--self-test" ]; then
|
|||||||
printf '%s %s\n' \
|
printf '%s %s\n' \
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000" "$target" \
|
"0000000000000000000000000000000000000000000000000000000000000000" "$target" \
|
||||||
>> "$WORK_DIR/pinprec.sha"
|
>> "$WORK_DIR/pinprec.sha"
|
||||||
apply_pinned_shas "$WORK_DIR/pinprec.sha" || exit 2
|
# Drive production extraction on a real historical ref whose body differs from the pin.
|
||||||
|
extract_baseline ff2994d9 pinprec || exit 2
|
||||||
got=$(awk -v n="$target" '$2 == n { print $1 }' "$WORK_DIR/pinprec.sha")
|
got=$(awk -v n="$target" '$2 == n { print $1 }' "$WORK_DIR/pinprec.sha")
|
||||||
if [ "$got" != "$pinned" ]; then
|
if [ "$got" != "$pinned" ]; then
|
||||||
say "PIN CONTROL FAILED: a baseline that carried a DIFFERENT sha for $target came out as"
|
say "PIN CONTROL FAILED: a baseline that carried a DIFFERENT sha for $target came out as"
|
||||||
@@ -552,7 +553,7 @@ if [ "${1:-}" = "--self-test" ]; then
|
|||||||
python3 "$PY" extract "$WORK_DIR/pinperturbed.cpp" "$ALL_FUNCTIONS" \
|
python3 "$PY" extract "$WORK_DIR/pinperturbed.cpp" "$ALL_FUNCTIONS" \
|
||||||
> "$WORK_DIR/pinperturbed.sha" || exit 2
|
> "$WORK_DIR/pinperturbed.sha" || exit 2
|
||||||
cp -f "$WORK_DIR/pristine.sha" "$WORK_DIR/pinbase.sha" || exit 2
|
cp -f "$WORK_DIR/pristine.sha" "$WORK_DIR/pinbase.sha" || exit 2
|
||||||
apply_pinned_shas "$WORK_DIR/pinbase.sha" || exit 2
|
extract_baseline HEAD pinbase || exit 2
|
||||||
if compare_lists "$WORK_DIR/pinbase.sha" "$WORK_DIR/pinperturbed.sha" \
|
if compare_lists "$WORK_DIR/pinbase.sha" "$WORK_DIR/pinperturbed.sha" \
|
||||||
"PIN($PINNED_BASELINE_REF)" "one-token-perturbed" 2> "$WORK_DIR/pinperturbed.err"; then
|
"PIN($PINNED_BASELINE_REF)" "one-token-perturbed" 2> "$WORK_DIR/pinperturbed.err"; then
|
||||||
say "NEGATIVE CONTROL DID NOT TRIP: one token was inserted into $target's body and the"
|
say "NEGATIVE CONTROL DID NOT TRIP: one token was inserted into $target's body and the"
|
||||||
|
|||||||
@@ -766,7 +766,8 @@ if [ "${1:-}" = "--self-test" ]; then
|
|||||||
printf '%s %s\n' \
|
printf '%s %s\n' \
|
||||||
"0000000000000000000000000000000000000000000000000000000000000000" "$target" \
|
"0000000000000000000000000000000000000000000000000000000000000000" "$target" \
|
||||||
>> "$WORK_DIR/pinprec.sha"
|
>> "$WORK_DIR/pinprec.sha"
|
||||||
apply_pinned_shas "$WORK_DIR/pinprec.sha" || exit 2
|
# Drive production extraction on a real historical ref whose body differs from the pin.
|
||||||
|
extract_baseline 37da3c3a pinprec || exit 2
|
||||||
got=$(awk -v n="$target" '$2 == n { print $1 }' "$WORK_DIR/pinprec.sha")
|
got=$(awk -v n="$target" '$2 == n { print $1 }' "$WORK_DIR/pinprec.sha")
|
||||||
if [ "$got" != "$pinned" ]; then
|
if [ "$got" != "$pinned" ]; then
|
||||||
say "PIN CONTROL FAILED: a baseline that carried a DIFFERENT sha for $target came out as"
|
say "PIN CONTROL FAILED: a baseline that carried a DIFFERENT sha for $target came out as"
|
||||||
@@ -789,7 +790,7 @@ if [ "${1:-}" = "--self-test" ]; then
|
|||||||
"$WORK_DIR/pinperturbed/$(blob_name "$targetSource")" token || exit 2
|
"$WORK_DIR/pinperturbed/$(blob_name "$targetSource")" token || exit 2
|
||||||
python3 "$PY" extract "$WORK_DIR/pinperturbed.spec" > "$WORK_DIR/pinperturbed.sha" || exit 2
|
python3 "$PY" extract "$WORK_DIR/pinperturbed.spec" > "$WORK_DIR/pinperturbed.sha" || exit 2
|
||||||
cp -f "$WORK_DIR/pristine.sha" "$WORK_DIR/pinbase.sha" || exit 2
|
cp -f "$WORK_DIR/pristine.sha" "$WORK_DIR/pinbase.sha" || exit 2
|
||||||
apply_pinned_shas "$WORK_DIR/pinbase.sha" || exit 2
|
extract_baseline HEAD pinbase || exit 2
|
||||||
if compare_lists "$WORK_DIR/pinbase.sha" "$WORK_DIR/pinperturbed.sha" \
|
if compare_lists "$WORK_DIR/pinbase.sha" "$WORK_DIR/pinperturbed.sha" \
|
||||||
"PIN($PINNED_BASELINE_REF)" "one-token-perturbed" 2> "$WORK_DIR/pinperturbed.err"; then
|
"PIN($PINNED_BASELINE_REF)" "one-token-perturbed" 2> "$WORK_DIR/pinperturbed.err"; then
|
||||||
say "NEGATIVE CONTROL DID NOT TRIP: one token was inserted into $target's body and the"
|
say "NEGATIVE CONTROL DID NOT TRIP: one token was inserted into $target's body and the"
|
||||||
|
|||||||
Reference in New Issue
Block a user