feat: add runner conversion scripts and strengthen cutover automation
This commit is contained in:
239
runners-conversion/periodVault/test-test-quality-gate.sh
Executable file
239
runners-conversion/periodVault/test-test-quality-gate.sh
Executable file
@@ -0,0 +1,239 @@
|
||||
#!/usr/bin/env bash
|
||||
# test-test-quality-gate.sh — Integration-style tests for validate-test-quality.sh.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
PASS_COUNT=0
|
||||
FAIL_COUNT=0
|
||||
declare -a TMP_REPOS=()
|
||||
|
||||
log() {
|
||||
echo "[test-quality-test] $*"
|
||||
}
|
||||
|
||||
pass() {
|
||||
PASS_COUNT=$((PASS_COUNT + 1))
|
||||
log "PASS: $*"
|
||||
}
|
||||
|
||||
fail() {
|
||||
FAIL_COUNT=$((FAIL_COUNT + 1))
|
||||
log "FAIL: $*"
|
||||
}
|
||||
|
||||
require_cmd() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
echo "Missing required command: $1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_expect_success() {
|
||||
local label="$1"
|
||||
shift
|
||||
if "$@" >/tmp/test-quality-gate.out 2>&1; then
|
||||
pass "$label"
|
||||
else
|
||||
fail "$label"
|
||||
cat /tmp/test-quality-gate.out
|
||||
fi
|
||||
}
|
||||
|
||||
run_expect_failure() {
|
||||
local label="$1"
|
||||
shift
|
||||
if "$@" >/tmp/test-quality-gate.out 2>&1; then
|
||||
fail "$label (expected failure but command succeeded)"
|
||||
cat /tmp/test-quality-gate.out
|
||||
else
|
||||
pass "$label"
|
||||
fi
|
||||
}
|
||||
|
||||
create_fixture_repo() {
|
||||
local repo
|
||||
repo="$(mktemp -d)"
|
||||
|
||||
mkdir -p "$repo/scripts" \
|
||||
"$repo/audit" \
|
||||
"$repo/androidApp/src/androidTest/kotlin/example" \
|
||||
"$repo/iosApp/iosAppUITests"
|
||||
|
||||
cp "$PROJECT_ROOT/scripts/validate-test-quality.sh" "$repo/scripts/"
|
||||
chmod +x "$repo/scripts/validate-test-quality.sh"
|
||||
|
||||
cat > "$repo/androidApp/src/androidTest/kotlin/example/ExampleUiTest.kt" <<'EOF'
|
||||
package example
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
class ExampleUiTest {
|
||||
@Test
|
||||
fun usesAntiPatternsForFixture() {
|
||||
Thread.sleep(5)
|
||||
try {
|
||||
// fixture-only
|
||||
} catch (e: AssertionError) {
|
||||
// fixture-only
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
cat > "$repo/iosApp/iosAppUITests/ExampleUiTests.swift" <<'EOF'
|
||||
import XCTest
|
||||
|
||||
final class ExampleUiTests: XCTestCase {
|
||||
func testFixtureUsesAntiPatterns() {
|
||||
sleep(1)
|
||||
if XCUIApplication().buttons["Example"].exists {
|
||||
XCTAssertTrue(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
cat > "$repo/audit/test-quality-baseline.json" <<'EOF'
|
||||
{
|
||||
"version": 1,
|
||||
"generated_at": "2026-02-20T16:00:00Z",
|
||||
"metrics": [
|
||||
{
|
||||
"id": "android_thread_sleep_calls",
|
||||
"description": "Android Thread.sleep",
|
||||
"mode": "rg",
|
||||
"root": "androidApp/src/androidTest",
|
||||
"glob": "*.kt",
|
||||
"pattern": "Thread\\.sleep\\(",
|
||||
"baseline": 1,
|
||||
"allowed_growth": 0
|
||||
},
|
||||
{
|
||||
"id": "android_assertionerror_catches",
|
||||
"description": "Android AssertionError catches",
|
||||
"mode": "rg",
|
||||
"root": "androidApp/src/androidTest",
|
||||
"glob": "*.kt",
|
||||
"pattern": "catch \\([^\\)]*AssertionError",
|
||||
"baseline": 1,
|
||||
"allowed_growth": 0
|
||||
},
|
||||
{
|
||||
"id": "ios_sleep_calls",
|
||||
"description": "iOS sleep calls",
|
||||
"mode": "rg",
|
||||
"root": "iosApp/iosAppUITests",
|
||||
"glob": "*.swift",
|
||||
"pattern": "\\bsleep\\(",
|
||||
"baseline": 1,
|
||||
"allowed_growth": 0
|
||||
},
|
||||
{
|
||||
"id": "ios_conditional_exists_guards_in_test_bodies",
|
||||
"description": "iOS conditional exists checks in test bodies",
|
||||
"mode": "swift_test_body_pattern",
|
||||
"root": "iosApp/iosAppUITests",
|
||||
"glob": "*.swift",
|
||||
"pattern": "if[[:space:]]+[^\\n]*\\.exists",
|
||||
"baseline": 1,
|
||||
"allowed_growth": 0
|
||||
},
|
||||
{
|
||||
"id": "ios_noop_assert_true",
|
||||
"description": "iOS no-op assertTrue(true) in test bodies",
|
||||
"mode": "swift_test_body_pattern",
|
||||
"root": "iosApp/iosAppUITests",
|
||||
"glob": "*.swift",
|
||||
"pattern": "XCTAssertTrue\\(true\\)",
|
||||
"baseline": 1,
|
||||
"allowed_growth": 0
|
||||
},
|
||||
{
|
||||
"id": "ios_empty_test_bodies",
|
||||
"description": "iOS empty or comment-only test bodies",
|
||||
"mode": "rg_multiline",
|
||||
"root": "iosApp/iosAppUITests",
|
||||
"glob": "*.swift",
|
||||
"pattern": "(?s)func\\s+test[[:alnum:]_]+\\s*\\([^)]*\\)\\s*(?:throws\\s*)?\\{\\s*(?:(?://[^\\n]*\\n)\\s*)*\\}",
|
||||
"baseline": 0,
|
||||
"allowed_growth": 0
|
||||
},
|
||||
{
|
||||
"id": "ios_placeholder_test_markers",
|
||||
"description": "iOS placeholder markers in test bodies",
|
||||
"mode": "swift_test_body_pattern",
|
||||
"root": "iosApp/iosAppUITests",
|
||||
"glob": "*.swift",
|
||||
"pattern": "(TODO|FIXME|placeholder|no-op)",
|
||||
"baseline": 0,
|
||||
"allowed_growth": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
|
||||
TMP_REPOS+=("$repo")
|
||||
echo "$repo"
|
||||
}
|
||||
|
||||
test_baseline_pass() {
|
||||
local repo
|
||||
repo="$(create_fixture_repo)"
|
||||
run_expect_success "validate-test-quality passes when metrics match baseline" \
|
||||
bash -lc "cd '$repo' && scripts/validate-test-quality.sh"
|
||||
}
|
||||
|
||||
test_growth_fails() {
|
||||
local repo
|
||||
repo="$(create_fixture_repo)"
|
||||
echo "Thread.sleep(10)" >> "$repo/androidApp/src/androidTest/kotlin/example/ExampleUiTest.kt"
|
||||
run_expect_failure "validate-test-quality fails when metric grows past threshold" \
|
||||
bash -lc "cd '$repo' && scripts/validate-test-quality.sh"
|
||||
}
|
||||
|
||||
test_allowed_growth_passes() {
|
||||
local repo
|
||||
repo="$(create_fixture_repo)"
|
||||
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
jq '(.metrics[] | select(.id == "ios_sleep_calls") | .allowed_growth) = 1' \
|
||||
"$repo/audit/test-quality-baseline.json" > "$tmp"
|
||||
mv "$tmp" "$repo/audit/test-quality-baseline.json"
|
||||
|
||||
echo "sleep(1)" >> "$repo/iosApp/iosAppUITests/ExampleUiTests.swift"
|
||||
|
||||
run_expect_success "validate-test-quality honors allowed_growth threshold" \
|
||||
bash -lc "cd '$repo' && scripts/validate-test-quality.sh"
|
||||
}
|
||||
|
||||
main() {
|
||||
require_cmd jq
|
||||
require_cmd rg
|
||||
require_cmd awk
|
||||
|
||||
test_baseline_pass
|
||||
test_growth_fails
|
||||
test_allowed_growth_passes
|
||||
|
||||
log "Summary: pass=$PASS_COUNT fail=$FAIL_COUNT"
|
||||
if [[ "$FAIL_COUNT" -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
local repo
|
||||
for repo in "${TMP_REPOS[@]:-}"; do
|
||||
[[ -d "$repo" ]] && rm -rf "$repo"
|
||||
done
|
||||
rm -f /tmp/test-quality-gate.out
|
||||
return 0
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user