Intelligently identify missing test coverage based on component type
This skill inherits all available tools. When active, it can use any tool Claude has access to.
README.mdThis skill automatically detects component type (networking, storage, API, etc.) and provides context-aware gap analysis. It analyzes e2e test files to identify missing test coverage specific to the component being tested.
Use this skill when you need to:
This skill MUST ALWAYS generate all three report formats (HTML, JSON, and Text) at runtime.
The gap analyzer script (generated at runtime to .work/test-coverage/gaps/gap_analyzer.py) performs the analysis and returns structured data. Claude Code is responsible for generating all three report formats based on this data.
Required Actions:
python3 .work/test-coverage/gaps/gap_analyzer.py <test-file> --output-json (outputs structured JSON to stdout)Failure to generate any of the three report formats should be treated as a skill execution failure.
# Python dependencies (standard library only, no external packages required)
# Ensure Python 3.8+ is installed
# Optional Go analysis tools
go install golang.org/x/tools/cmd/guru@latest
go install golang.org/x/tools/cmd/goimports@latest
Note: This skill currently supports E2E/integration test files for OpenShift/Kubernetes components written in Go (Ginkgo framework).
The analyzer performs single test file analysis with two analysis layers:
Generic Coverage Analysis (keyword-based)
Feature-Based Analysis (runtime extraction)
It does not perform repository traversal, Go AST parsing, or test-to-source mapping.
The analyzer automatically detects the component type from:
File path patterns:
/networking/ → networking component/storage/ → storage component/kapi/, /api/ → kube-api component/etcd/ → etcd component/auth/, /rbac/ → auth componentFile content patterns:
sig-networking, networkpolicy, egressip → networkingsig-storage, persistentvolume → storagesig-api, apiserver → kube-apiParses the test file using regex to extract:
g.It("test name") patterns[Serial], [Disruptive], [NonPreRelease]-12345- in test namesExample:
g.It("egressip-12345-should work on AWS [Serial]", func() {
// Test implementation
})
Extracted:
egressip-12345-should work on AWS [Serial]12345[Serial]For each component type, the analyzer searches the file content for specific keywords to determine what is tested:
Networking components:
vsphere, AWS, azure, GCP, baremetalTCP, UDP, SCTPNodePort, LoadBalancer, ClusterIPinvalid, upgrade, concurrent, performance, rbacStorage components:
vsphere, AWS, azure, GCP, baremetalgp2, gp3, csiReadWriteOnce, ReadWriteMany, ReadOnlyManyinvalid, upgrade, concurrent, performance, rbacOther components:
vsphere, AWS, azure, GCP, baremetalinvalid, upgrade, concurrent, performance, rbacFor each coverage dimension, if a keyword is not found in the file, it's flagged as a gap:
Example:
# If file content doesn't contain "azure" (case-insensitive)
gaps.append({
'platform': 'Azure',
'priority': 'high',
'impact': 'Major cloud provider - production blocker',
'recommendation': 'Add Azure platform-specific tests'
})
Scoring is component-specific to avoid penalizing components for irrelevant metrics:
Networking components:
Storage components:
Other components:
Each dimension score = (items_found / total_items) × 100
In addition to the keyword-based coverage analysis above, the analyzer performs dynamic feature extraction to identify component-specific features from test names at runtime, without any hardcoded feature matrices.
How Runtime Feature Extraction Works:
Extract Features from Test Names
Parse test names to identify features being tested:
Example Test Name:
"Validate egressIP with mixed of multiple non-overlapping UDNs and default network(layer3/2 and IPv4 only)"
Extracted Features:
Group Features into Categories
Features are automatically categorized:
Infer Missing Features
Based on patterns, infer what's missing:
Benefits of Runtime Feature Extraction:
✅ No Hardcoding - Works for ANY component without configuration ✅ Intelligent Gap Detection - Infers missing features based on patterns ✅ Component-Agnostic - Automatically adapts to any component type ✅ Always Current - Extracts from actual test names, not assumed features
Example: EgressIP Test Analysis
Input (Test Names):
1. Validate egressIP with mixed of multiple non-overlapping UDNs
2. Validate egressIP with mixed of multiple overlapping UDNs
3. Validate egressIP Failover with UDNs
4. egressIP after UDN deleted then recreated
5. egressIP after OVNK restarted
6. Traffic is load balanced between egress nodes
Output (Extracted Features):
Configuration Patterns:
✓ Non-overlapping configuration
✓ Overlapping configuration
✓ Multiple resource configuration
✓ Mixed configuration
Network Topology:
✓ User Defined Networks (UDN)
Lifecycle Operations:
✓ Resource deletion
✓ Resource recreation
Network Features:
✓ Failover
✓ Load balancing
Resilience & Recovery:
✓ OVN-Kubernetes restart
Output (Inferred Feature Gaps):
[HIGH] Single resource configuration
- Pattern suggests "multiple" tested but not "single"
- Recommendation: Add single resource baseline tests
[HIGH] Layer 2 networking
- Layer 3 tested but Layer 2 missing
- Recommendation: Add Layer 2 network topology tests
[MEDIUM] Local gateway mode
- Gateway mode mentioned but local vs shared not clear
- Recommendation: Add explicit gateway mode tests
Integration in gap_analyzer.py:
The dynamic feature extractor is built into the analyzer (no separate import needed):
# After extracting test cases
feature_analysis = extract_features_from_tests(test_cases)
# Results included in analysis output
tested_features = feature_analysis['tested_features']
# {'Configuration Patterns': ['Overlapping', 'Non-overlapping', ...],
# 'Network Topology': ['UDN', 'Layer3', ...]}
feature_gaps = feature_analysis['feature_gaps']
# [{'feature': 'Multiple resources', 'priority': 'high', ...}]
coverage_stats = feature_analysis['coverage_stats']
# {'features_tested': 14, 'features_missing': 5}
Report Integration:
Feature analysis is included in all three report formats:
The current implementation has the following limitations:
❌ No repository traversal - Analyzes only the single test file provided as input ❌ No Go AST parsing - Uses regex pattern matching instead of parsing Go syntax trees ❌ No test-to-source mapping - Cannot map test functions to source code functions ❌ No function-level coverage - Cannot determine which source functions are tested ❌ No project-wide analysis - Cannot analyze multiple test files or aggregate results ❌ Keyword-based detection only - Gap detection relies on keyword presence in test file ❌ Single file focus - Reports cover only the analyzed test file, not the entire codebase
These limitations mean the analyzer provides scenario and platform coverage analysis for a single E2E test file, not structural code coverage across a codebase.
The analyzer generates three report formats. You should generate Python code at runtime to create these reports.
test-gaps-report.html)Purpose: Interactive, filterable HTML report for visual gap analysis with professional styling
HTML Document Structure:
Generate a complete HTML5 document with the following structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test Coverage Gap Analysis - {filename}</title>
<style>
/* Inline all CSS styles here - see CSS Styles section below */
</style>
</head>
<body>
<div class="container">
<!-- Content sections -->
</div>
<script>
/* JavaScript for gap filtering - see JavaScript section below */
</script>
</body>
</html>
CSS Styles (Inline in <style> tag):
Generate comprehensive CSS with the following style rules:
Reset and Base Styles:
*: box-sizing: border-box, margin: 0, padding: 0body: font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; color: #333; background: #f5f5f5; padding: 20pxContainer and Layout:
.container: max-width: 1400px, margin: 0 auto, background: white, padding: 30px, border-radius: 8px, box-shadow: 0 2px 10px rgba(0,0,0,0.1)h1: color: #2c3e50, margin-bottom: 10px, font-size: 2emh2: color: #34495e, margin-top: 30px, margin-bottom: 15px, padding-bottom: 10px, border-bottom: 2px solid #e74c3c, font-size: 1.5emh3: color: #34495e, margin-top: 20px, margin-bottom: 10px, font-size: 1.2emMetadata Section:
.metadata: background: #ecf0f1, padding: 15px, border-radius: 5px, margin-bottom: 25px.metadata p: margin: 5px 0Score Cards:
.score-grid: display: grid, grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)), gap: 15px, margin: 20px 0.score-card: padding: 20px, border-radius: 8px, text-align: center, color: white.score-card.excellent: background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%) (score >= 80).score-card.good: background: linear-gradient(135deg, #3498db 0%, #2980b9 100%) (score >= 60).score-card.fair: background: linear-gradient(135deg, #f39c12 0%, #e67e22 100%) (score >= 40).score-card.poor: background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%) (score < 40).score-card .number: font-size: 2.5em, font-weight: bold, margin: 10px 0.score-card .label: font-size: 0.9em, opacity: 0.9Gap Cards:
.gap-card: background: #fff, border-left: 4px solid #e74c3c, padding: 20px, margin: 15px 0, border-radius: 5px, box-shadow: 0 2px 5px rgba(0,0,0,0.1).gap-card.high: border-left-color: #e74c3c.gap-card.medium: border-left-color: #f39c12.gap-card.low: border-left-color: #3498db.gap-card h4: color: #2c3e50, margin-bottom: 10px, font-size: 1.1em.gap-card .gap-id: font-family: "Courier New", monospace, font-size: 0.85em, color: #7f8c8d, margin-bottom: 5px.priority: display: inline-block, padding: 4px 12px, border-radius: 12px, font-size: 0.75em, font-weight: bold, margin-right: 8px.priority.high: background: #e74c3c, color: white.priority.medium: background: #f39c12, color: white.priority.low: background: #3498db, color: white.gap-card .impact: background: #fff3cd, border-left: 3px solid #ffc107, padding: 10px, margin: 10px 0, border-radius: 3px.gap-card .recommendation: background: #d4edda, border-left: 3px solid #28a745, padding: 10px, margin: 10px 0, border-radius: 3pxTables:
table: width: 100%, border-collapse: collapse, margin: 20px 0th, td: padding: 12px, text-align: left, border-bottom: 1px solid #dddth: background: #34495e, color: white, font-weight: 600tr:hover: background: #f5f5f5.tested: background: #d4edda, color: #155724, font-weight: bold, text-align: center.not-tested: background: #f8d7da, color: #721c24, font-weight: bold, text-align: centerSummary Boxes:
.summary-box: background: #e3f2fd, border-left: 4px solid #2196f3, padding: 15px, margin: 20px 0, border-radius: 5px.warning-box: background: #fff3cd, border-left: 4px solid #ffc107, padding: 15px, margin: 20px 0, border-radius: 5px.success-box: background: #d4edda, border-left: 4px solid #28a745, padding: 15px, margin: 20px 0, border-radius: 5pxFilter Buttons:
.filter-buttons: margin: 20px 0.filter-btn: padding: 10px 20px, margin-right: 10px, border: none, border-radius: 5px, cursor: pointer, font-weight: bold.filter-btn.active: box-shadow: 0 0 0 3px rgba(0,0,0,0.2).filter-btn.all: background: #95a5a6, color: white.filter-btn.high: background: #e74c3c, color: white.filter-btn.medium: background: #f39c12, color: white.filter-btn.low: background: #3498db, color: whiteHTML Content Sections:
Metadata Section:
<div class="metadata">
<p><strong>File:</strong> <code>{escaped_filename}</code></p>
<p><strong>Path:</strong> <code>{escaped_filepath}</code></p>
<p><strong>Component:</strong> {escaped_component_title}</p>
<p><strong>Analysis Date:</strong> {YYYY-MM-DD}</p>
<p><strong>Total Test Cases:</strong> {count}</p>
</div>
Coverage Scores Section:
SCORE_DISPLAY = {
'overall': {'order': 1, 'label': 'Overall Coverage'},
'platform_coverage': {'order': 2, 'label': 'Platform Coverage'},
'ip_stack_coverage': {'order': 3, 'label': 'IP Stack Coverage'},
'topology_coverage': {'order': 4, 'label': 'Topology Coverage'},
'network_layer_coverage': {'order': 5, 'label': 'Network Layer Coverage'},
'gateway_mode_coverage': {'order': 6, 'label': 'Gateway Mode Coverage'},
'protocol_coverage': {'order': 5, 'label': 'Protocol Coverage'},
'service_type_coverage': {'order': 6, 'label': 'Service Type Coverage'},
'storage_class_coverage': {'order': 7, 'label': 'Storage Class Coverage'},
'volume_mode_coverage': {'order': 8, 'label': 'Volume Mode Coverage'},
'scenario_coverage': {'order': 99, 'label': 'Scenario Coverage'},
}
get_score_class(score)What's Tested Section:
<table>
<tr>
<th>Item</th>
<th>Status</th>
</tr>
<tr>
<td>AWS</td>
<td class="tested">✓ Tested</td>
</tr>
</table>
Coverage Gaps Section:
<div class="gap-card {priority}" data-priority="{priority}">
<div class="gap-id">GAP-{001}</div>
<h4>
<span class="priority {priority}">{PRIORITY} PRIORITY</span>
<span class="category">{Category}</span>
{gap_name}
</h4>
<div class="impact"><strong>Impact:</strong> {impact_description}</div>
<div class="recommendation"><strong>Recommendation:</strong> {recommendation_text}</div>
</div>
Recommendations Section:
JavaScript for Filtering (Inline in <script> tag):
function filterGaps(priority) {
const cards = document.querySelectorAll('.gap-card');
const buttons = document.querySelectorAll('.filter-btn');
buttons.forEach(btn => btn.classList.remove('active'));
document.querySelector(`.filter-btn.${priority}`).classList.add('active');
cards.forEach(card => {
if (priority === 'all' || card.dataset.priority === priority) {
card.style.display = 'block';
} else {
card.style.display = 'none';
}
});
}
Security Requirements:
html.escape() for all user-provided content (filenames, test names, gap descriptions)Helper Functions to Implement:
get_score_class(score):
Escape all strings using from html import escape
Component-Specific Behavior:
Networking components (networking, router, dns, network-observability):
Storage components (storage, csi):
Other components:
test-gaps-report.json)Generated by: Claude Code at runtime based on analyzer output
Purpose: Machine-readable format for CI/CD integration
Structure:
{
"analysis": {
"file": "path/to/test/file.go",
"component_type": "networking",
"test_count": 15,
"test_cases": [
{
"name": "test name",
"line": 42,
"id": "12345",
"tags": ["Serial", "Disruptive"]
}
],
"coverage": {
"platforms": {
"tested": ["AWS", "GCP"],
"not_tested": ["Azure", "vSphere", "Bare Metal"]
},
"protocols": {
"tested": ["TCP"],
"not_tested": ["UDP", "SCTP"]
}
},
"gaps": {
"platforms": [
{
"platform": "Azure",
"priority": "high",
"impact": "Major cloud provider",
"recommendation": "Add Azure tests"
}
],
"protocols": [],
"scenarios": []
}
},
"scores": {
"overall": 45.0,
"platform_coverage": 33.3,
"protocol_coverage": 33.3,
"scenario_coverage": 40.0
},
"generated_at": "2025-11-10T10:00:00Z"
}
Implementation: Use json.dump() with indent=2 for readable output
test-gaps-summary.txt)Generated by: Claude Code at runtime based on analyzer output
Purpose: Terminal-friendly summary for quick review
Format Structure:
============================================================
Test Coverage Gap Analysis
============================================================
File: {filename}
Component: {component_type}
Test Cases: {count}
Analysis Date: {timestamp}
============================================================
Coverage Scores
============================================================
Overall Coverage: {score}%
Platform Coverage: {score}%
[Component-specific scores based on type]
Scenario Coverage: {score}%
============================================================
What's Tested
============================================================
Platforms:
✓ {platform1}
✓ {platform2}
[Additional tested items based on component type]
============================================================
Identified Gaps
============================================================
PLATFORM GAPS:
[PRIORITY] {platform}
Impact: {impact}
Recommendation: {recommendation}
[Additional gap sections based on component type]
============================================================
Recommendations
============================================================
Current Coverage: {current}%
Target Coverage: {target}%
Focus on addressing HIGH priority gaps first to maximize
test coverage and ensure production readiness.
Component-Specific Sections:
Implementation: Use '\n'.join(lines) to build the text content
When implementing this skill in a command:
CRITICAL: Before running any analysis, generate the analyzer script from the reference implementation.
# Create output directory
mkdir -p .work/test-coverage/gaps/
# Generate the analyzer script from the specification below
# Claude Code will write gap_analyzer.py based on the Analyzer Specification section
Analyzer Specification:
Generate a Python script (gap_analyzer.py) that performs component-aware E2E test gap analysis:
Input: Path or URL to a Go test file (Ginkgo framework) Output: JSON to stdout with analysis results and coverage scores
Core Algorithm:
Input Processing (handle URLs and local paths):
http:// or https://urllib.request.urlopen() to fetch content, save to temp fileComponent Detection (auto-detect from file path/content):
/networking/, egressip, networkpolicy → component_type='networking'/storage/, persistentvolume → component_type='storage'Test Extraction (regex-based):
(?:g\.|o\.)?It\(\s*["']([^"']+)["']-\d+-)Coverage Analysis (keyword search in file content):
aws|azure|gcp|vsphere|baremetal|rosa (case-insensitive)\bTCP\b, \bUDP\b, \bSCTP\b, curl|wget|http (TCP via HTTP)ipv4, ipv6, dualstackNodePort, LoadBalancer, ClusterIPlayer2|l2, layer3|l3, default networklocal.gateway|lgw → if found, Local Gateway is testedsno|single-node, multi-node|HA cluster, hypershift|hcp, check NonHyperShiftHOST tagfailover, reboot, restart, delete, invalid, upgrade, concurrent, performance, rbac, traffic disruptionGap Identification:
Coverage Scoring (component-aware):
Output Format (JSON to stdout):
{
"analysis": {
"file": "/path/to/test.go",
"component_type": "networking",
"test_count": 15,
"test_cases": [...],
"coverage": {
"platforms": {"tested": [...], "not_tested": [...]},
"protocols": {"tested": [...], "not_tested": [...]},
...
},
"gaps": {
"platforms": [{"platform": "Azure", "priority": "high", "impact": "...", "recommendation": "..."}],
...
}
},
"scores": {
"overall": 62.0,
"platform_coverage": 100.0,
...
}
}
Why Runtime Generation:
.py file to maintainExecute the gap analyzer script to perform analysis and return structured data:
# Run gap analyzer (outputs structured JSON to stdout)
python3 .work/test-coverage/gaps/gap_analyzer.py <test-file-path> --output-json
The analyzer will output structured JSON to stdout containing:
IMPORTANT: Do not skip this step. Do not attempt manual analysis. The script is the authoritative implementation.
import json
import subprocess
# Run analyzer and capture JSON output
result = subprocess.run(
['python3', '.work/test-coverage/gaps/gap_analyzer.py', test_file, '--output-json'],
capture_output=True,
text=True
)
# Parse structured data
analysis_data = json.loads(result.stdout)
IMPORTANT: Claude Code generates all three report formats based on the analyzer's structured output.
json_path = '.work/test-coverage/gaps/test-gaps-report.json'
with open(json_path, 'w') as f:
json.dump(analysis_data, f, indent=2)
Follow the text format specification in Step 6 to generate a terminal-friendly summary.
text_path = '.work/test-coverage/gaps/test-gaps-summary.txt'
# Generate text content following format in Step 6
with open(text_path, 'w') as f:
f.write(text_content)
Follow the HTML specification in Step 6 to generate an interactive report.
html_path = '.work/test-coverage/gaps/test-gaps-report.html'
# Generate HTML content following specification in Step 6
# Include all CSS styles, JavaScript filtering, and component-specific sections
with open(html_path, 'w') as f:
f.write(html_content)
Key Requirements:
<style> tag<script> taghtml.escape()After generating all three reports, display the results to the user:
# Display summary (from text report or analysis_data)
print(f"Component detected: {analysis_data['analysis']['component_type']}")
print(f"Overall coverage: {analysis_data['scores']['overall']}%")
print(f"High-priority gaps: {high_priority_count}")
# Provide report locations
print("\nReports Generated:")
print(" ✓ HTML: .work/test-coverage/gaps/test-gaps-report.html")
print(" ✓ JSON: .work/test-coverage/gaps/test-gaps-report.json")
print(" ✓ Text: .work/test-coverage/gaps/test-gaps-summary.txt")
For programmatic access to gap data, use the analysis_data from Step 2:
# Access analysis results (from analysis_data captured in Step 2)
component_type = analysis_data['analysis']['component_type']
test_count = analysis_data['analysis']['test_count']
overall_score = analysis_data['scores']['overall']
# Access gaps
platform_gaps = analysis_data['analysis']['gaps']['platforms']
protocol_gaps = analysis_data['analysis']['gaps'].get('protocols', [])
scenario_gaps = analysis_data['analysis']['gaps']['scenarios']
# Filter high-priority gaps
high_priority_gaps = [
gap for category in analysis_data['analysis']['gaps'].values()
for gap in category if gap.get('priority') == 'high'
]
CRITICAL: Before declaring this skill complete, you MUST execute ALL validation checks below. Failure to validate is considered incomplete execution.
Execute these verification steps in order. ALL must pass:
# Verify all three reports exist
test -f .work/test-coverage/gaps/test-gaps-report.html && echo "✓ HTML exists" || echo "✗ HTML MISSING"
test -f .work/test-coverage/gaps/test-gaps-report.json && echo "✓ JSON exists" || echo "✗ JSON MISSING"
test -f .work/test-coverage/gaps/test-gaps-summary.txt && echo "✓ Text exists" || echo "✗ Text MISSING"
Required: All three files must exist. If any are missing, regenerate them.
# Verify HTML has "Tested Features (Dynamic Feature Extraction)" section
grep -q "Tested Features (Dynamic Feature Extraction)" .work/test-coverage/gaps/test-gaps-report.html && \
echo "✓ Feature extraction section present" || \
echo "✗ MISSING: Dynamic Feature Extraction section"
# Verify JSON has feature data
grep -q '"tested_features"' .work/test-coverage/gaps/test-gaps-report.json && \
grep -q '"feature_gaps"' .work/test-coverage/gaps/test-gaps-report.json && \
echo "✓ Feature data in JSON" || \
echo "✗ MISSING: Feature data in JSON"
# Verify Text has feature section
grep -q "Tested Features" .work/test-coverage/gaps/test-gaps-summary.txt && \
echo "✓ Feature section in Text" || \
echo "✗ MISSING: Feature section in Text"
Required: Dynamic Feature Extraction must be present in all three reports. This is a critical requirement from Step 5a (lines 163-280).
CRITICAL: The HTML report must display ALL coverage dimension tables based on component type.
# For networking components, verify ALL 8 dimension tables exist
grep -c "<h3>Platforms</h3>" .work/test-coverage/gaps/test-gaps-report.html
grep -c "<h3>Protocols</h3>" .work/test-coverage/gaps/test-gaps-report.html
grep -c "<h3>Service Types</h3>" .work/test-coverage/gaps/test-gaps-report.html
grep -c "<h3>IP Stacks</h3>" .work/test-coverage/gaps/test-gaps-report.html
grep -c "<h3>Network Layers</h3>" .work/test-coverage/gaps/test-gaps-report.html
grep -c "<h3>Gateway Modes</h3>" .work/test-coverage/gaps/test-gaps-report.html
grep -c "<h3>Topologies</h3>" .work/test-coverage/gaps/test-gaps-report.html
grep -c "<h3>Scenarios</h3>" .work/test-coverage/gaps/test-gaps-report.html
Expected Results:
Verification Command:
# Count total coverage dimension tables
TABLE_COUNT=$(grep -E "<h3>(Platforms|Protocols|Service Types|IP Stacks|Network Layers|Gateway Modes|Topologies|Scenarios|Storage Classes|Volume Modes|Provisioners)</h3>" .work/test-coverage/gaps/test-gaps-report.html | wc -l)
echo "Coverage dimension tables found: $TABLE_COUNT"
# Verify based on component type
COMPONENT=$(grep -oP 'Component:</strong> \K[^<]+' .work/test-coverage/gaps/test-gaps-report.html | head -1 | tr -d '</p>')
echo "Component type: $COMPONENT"
case "$COMPONENT" in
Networking)
[ "$TABLE_COUNT" -eq 8 ] && echo "✓ All 8 networking dimensions present" || echo "✗ INCOMPLETE: Expected 8 tables, found $TABLE_COUNT"
;;
Storage)
[ "$TABLE_COUNT" -eq 5 ] && echo "✓ All 5 storage dimensions present" || echo "✗ INCOMPLETE: Expected 5 tables, found $TABLE_COUNT"
;;
*)
[ "$TABLE_COUNT" -eq 2 ] && echo "✓ All 2 generic dimensions present" || echo "✗ INCOMPLETE: Expected 2 tables, found $TABLE_COUNT"
;;
esac
Required: All component-specific dimension tables must be present. Missing tables indicate incomplete HTML generation.
# Verify gaps include effort estimates
grep -q "Effort Required" .work/test-coverage/gaps/test-gaps-report.html && \
echo "✓ Effort estimates in HTML" || \
echo "✗ MISSING: Effort estimates"
Required: Gaps must include effort estimates (Low, Medium, High) as specified in Step 5a.
# Verify analyzer has feature extraction function
grep -q "def extract_features_from_tests" .work/test-coverage/gaps/gap_analyzer.py && \
echo "✓ Feature extraction function exists" || \
echo "✗ MISSING: extract_features_from_tests() function"
# Verify all 5 feature categories are defined
grep -q "Configuration Patterns" .work/test-coverage/gaps/gap_analyzer.py && \
grep -q "Network Topology" .work/test-coverage/gaps/gap_analyzer.py && \
grep -q "Lifecycle Operations" .work/test-coverage/gaps/gap_analyzer.py && \
grep -q "Network Features" .work/test-coverage/gaps/gap_analyzer.py && \
grep -q "Resilience & Recovery" .work/test-coverage/gaps/gap_analyzer.py && \
echo "✓ All 5 feature categories defined" || \
echo "✗ MISSING: Some feature categories not implemented"
Required: The gap analyzer must implement Dynamic Feature Extraction with all 5 categories.
# Verify JSON has all required fields
python3 << 'EOF'
import json
try:
with open('.work/test-coverage/gaps/test-gaps-report.json', 'r') as f:
data = json.load(f)
required_fields = [
('analysis.file', lambda d: d['analysis']['file']),
('analysis.component_type', lambda d: d['analysis']['component_type']),
('analysis.test_count', lambda d: d['analysis']['test_count']),
('analysis.tested_features', lambda d: d['analysis']['tested_features']),
('analysis.feature_gaps', lambda d: d['analysis']['feature_gaps']),
('scores.overall', lambda d: d['scores']['overall']),
]
missing = []
for name, getter in required_fields:
try:
getter(data)
print(f"✓ {name}")
except (KeyError, TypeError):
print(f"✗ MISSING: {name}")
missing.append(name)
if not missing:
print("\n✓ All required JSON fields present")
else:
print(f"\n✗ INCOMPLETE: Missing {len(missing)} required fields")
exit(1)
except Exception as e:
print(f"✗ ERROR: {e}")
exit(1)
EOF
Required: All required JSON fields must be present.
Before declaring this skill complete:
If ANY check fails: Fix the issue and re-run all validation checks. Do NOT declare the skill complete until ALL checks pass.
File not found:
Invalid file format:
.go)g.It, g.Describe)No test cases found:
g.It("...") patterns# Run gap analyzer on a networking test file
cd /home/anusaxen/git/ai-helpers/plugins/test-coverage
python3 .work/test-coverage/gaps/gap_analyzer.py \
/path/to/test/extended/networking/egressip_test.go \
--output .work/gaps/
# Output:
# Component detected: networking
# Test cases found: 25
# Overall coverage: 45.0%
# High-priority gaps: Azure platform, UDP protocol, Error handling scenarios
#
# Reports generated:
# HTML: .work/gaps/test-gaps-report.html
# JSON: .work/gaps/test-gaps-report.json
# Text: .work/gaps/test-gaps-summary.txt
# Run gap analyzer on a storage test file
python3 .work/test-coverage/gaps/gap_analyzer.py \
/path/to/test/extended/storage/persistent_volumes_test.go \
--output .work/gaps/
# Output:
# Component detected: storage
# Test cases found: 18
# Overall coverage: 52.0%
# High-priority gaps: ReadWriteMany volumes, CSI storage class, Snapshot scenarios
# Analyze file from GitHub raw URL
python3 .work/test-coverage/gaps/gap_analyzer.py \
https://raw.githubusercontent.com/openshift/origin/master/test/extended/networking/egressip.go \
--output .work/gaps/
The analyzer automatically detects URLs and downloads the file for analysis.
This skill is used by:
/test-coverage:gaps <test-file-or-url> - Analyze E2E test scenario gapsThe command invokes this skill to perform component-aware gap analysis on the specified test file.