Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions scripts/tests/bugbot-gate-mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@
("a repeating cursor is followed for ever instead of refused",
' if not cursor or cursor in seen_cursors or pages_left <= 0:',
' if not cursor:'),
# The regression the staging-hop Bugbot named on #464: the pageInfo self-check
# going blind for ONE connection. The selftest's stripper loop used to `break`
# after `checkSuites`, and its `reviewThreads` branch pasted a fixed indentation
# that matched the checkSuites line first -- so this row was UNCAUGHT until
# the loop was made to visit every member (measured before the fix landed).
("the pageInfo self-check walks only the first connection, so reviewThreads' "
"cursor can be dropped from the query unnoticed",
' for name in PAGED_TOPLEVEL:\n match = re.search(name + r"\\(first:',
' for name in list(PAGED_TOPLEVEL)[:1]:\n match = re.search(name + r"\\(first:'),

# --- (A) the load-bearing claim: a TERMINAL verdict on THIS head --------
("a missing Bugbot verdict reports PASS instead of UNCLAIMED",
Expand Down
55 changes: 47 additions & 8 deletions scripts/tests/bugbot-gate-selftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -911,15 +911,54 @@ def _threads(n, start=0):
# The query must keep asking for pageInfo, or none of the above ever runs live.
check("the real QUERY asks both top-level connections for pageInfo",
gate.connections_missing_pageinfo() == [], "missing=%r" % gate.connections_missing_pageinfo())

# EVERY CONNECTION, AND THE RIGHT ONE. The first version of this loop ended in a
# `break`, so only the first member of PAGED_TOPLEVEL (`checkSuites`) was ever
# exercised, and its `reviewThreads` branch pasted a fixed 6-space indentation
# into `str.replace` -- a needle that is a substring of the 14-space-indented
# `checkSuites` line and so, had it ever run, would have stripped checkSuites'
# pageInfo a second time and let the detector "pass" by naming the wrong
# connection (measured: `connections_missing_pageinfo` answered
# `['checkSuites']` for the reviewThreads branch). A self-check that went blind
# for `reviewThreads` alone passed this suite. Same shape as the totalCount
# stripper above, with three things pinned:
# 1. the members are ALSO written down as literals, because a loop over the
# module's own dict cannot see a member being removed from it;
# 2. the stripper is anchored on the connection's own name and is indentation-
# agnostic, and its substitution count is asserted, so it cannot hit the
# neighbour or silently strip nothing;
# 3. the detector must name EXACTLY the connection stripped -- the other one,
# or both, is a wrong answer, not a pass;
# and the loop's visit list is compared to the literals afterwards, so a `break`
# (or a `continue` past the asserts) reddens the suite instead of shrinking it.
PAGED_TOPLEVEL_LITERALS = ("checkSuites", "reviewThreads")
for name in PAGED_TOPLEVEL_LITERALS:
check(
"%r is declared a paged top-level connection" % name,
name in gate.PAGED_TOPLEVEL,
"PAGED_TOPLEVEL = %r" % (list(gate.PAGED_TOPLEVEL),),
)
pageinfo_visited = []
for name in gate.PAGED_TOPLEVEL:
stripped = re.sub(r"pageInfo \{ hasNextPage endCursor \}\n", "", gate.QUERY, count=1) \
if name == "checkSuites" else gate.QUERY.replace(" pageInfo { hasNextPage endCursor }\n", "", 1)
# Whichever occurrence the stripper removed, the guard must name AT LEAST one
# connection -- the assertion is that the stripper applied and was seen.
check("the pageInfo stripper actually applied", stripped != gate.QUERY)
check("dropping pageInfo from the query is detected",
gate.connections_missing_pageinfo(stripped) != [], "guard stayed silent for %r" % name)
break
stripped, applied = re.subn(
r"(" + name + r"\(first:\s*\d+[^)]*\)\s*\{[^{]*?)pageInfo\s*\{[^}]*\}\s*", r"\1", gate.QUERY
)
check(
"the pageInfo stripper actually applied to %r" % name,
applied == 1,
"%d substitution(s) -- the anchor no longer matches the query" % applied,
)
check(
"dropping pageInfo from %r is detected, and %r alone is named" % (name, name),
gate.connections_missing_pageinfo(stripped) == [name],
"detector said %r" % (gate.connections_missing_pageinfo(stripped),),
)
pageinfo_visited.append(name)
check(
"the pageInfo stripper loop visited every paged top-level connection",
sorted(pageinfo_visited) == sorted(PAGED_TOPLEVEL_LITERALS),
"visited %r, expected %r" % (pageinfo_visited, list(PAGED_TOPLEVEL_LITERALS)),
)

# 7. severity_of, directly.
# --------------------------------------------------------------------------
Expand Down
Loading