chore: git cache cleanup
This commit is contained in:
@@ -0,0 +1,293 @@
|
||||
# Sprint 1 - E2E Test Timeout Remediation Findings
|
||||
|
||||
**Date**: 2026-02-02
|
||||
**Status**: In Progress
|
||||
**Sprint**: Sprint 1 (Quick Fixes - Priority Implementation)
|
||||
|
||||
## Implemented Changes
|
||||
|
||||
### ✅ Fix 1.1 + Fix 1.1b: Remove beforeEach polling, add afterEach cleanup
|
||||
|
||||
**File**: `tests/settings/system-settings.spec.ts`
|
||||
|
||||
**Changes Made**:
|
||||
1. **Removed** `waitForFeatureFlagPropagation()` call from `beforeEach` hook (lines 35-46)
|
||||
- This was causing 10s × 31 tests = 310s of polling overhead per shard
|
||||
- Commented out with clear explanation linking to remediation plan
|
||||
|
||||
2. **Added** `test.afterEach()` hook with direct API state restoration:
|
||||
```typescript
|
||||
test.afterEach(async ({ page }) => {
|
||||
await test.step('Restore default feature flag state', async () => {
|
||||
const defaultFlags = {
|
||||
'cerberus.enabled': true,
|
||||
'crowdsec.console_enrollment': false,
|
||||
'uptime.enabled': false,
|
||||
};
|
||||
|
||||
// Direct API mutation to reset flags (no polling needed)
|
||||
await page.request.put('/api/v1/feature-flags', {
|
||||
data: defaultFlags,
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Rationale**:
|
||||
- Tests already verify feature flag state individually after toggle actions
|
||||
- Initial state verification in beforeEach was redundant
|
||||
- Explicit cleanup in afterEach ensures test isolation without polling overhead
|
||||
- Direct API mutation for state restoration is faster than polling
|
||||
|
||||
**Expected Impact**:
|
||||
- 310s saved per shard (10s × 31 tests)
|
||||
- Elimination of inter-test dependencies
|
||||
- No state leakage between tests
|
||||
|
||||
### ✅ Fix 1.3: Implement request coalescing with fixed cache
|
||||
|
||||
**File**: `tests/utils/wait-helpers.ts`
|
||||
|
||||
**Changes Made**:
|
||||
|
||||
1. **Added module-level cache** for in-flight requests:
|
||||
```typescript
|
||||
// Cache for in-flight requests (per-worker isolation)
|
||||
const inflightRequests = new Map<string, Promise<Record<string, boolean>>>();
|
||||
```
|
||||
|
||||
2. **Implemented cache key generation** with sorted keys and worker isolation:
|
||||
```typescript
|
||||
function generateCacheKey(
|
||||
expectedFlags: Record<string, boolean>,
|
||||
workerIndex: number
|
||||
): string {
|
||||
// Sort keys to ensure {a:true, b:false} === {b:false, a:true}
|
||||
const sortedFlags = Object.keys(expectedFlags)
|
||||
.sort()
|
||||
.reduce((acc, key) => {
|
||||
acc[key] = expectedFlags[key];
|
||||
return acc;
|
||||
}, {} as Record<string, boolean>);
|
||||
|
||||
// Include worker index to isolate parallel processes
|
||||
return `${workerIndex}:${JSON.stringify(sortedFlags)}`;
|
||||
}
|
||||
```
|
||||
|
||||
3. **Modified `waitForFeatureFlagPropagation()`** to use cache:
|
||||
- Returns cached promise if request already in flight for worker
|
||||
- Logs cache hits/misses for observability
|
||||
- Removes promise from cache after completion (success or failure)
|
||||
|
||||
4. **Added cleanup function**:
|
||||
```typescript
|
||||
export function clearFeatureFlagCache(): void {
|
||||
inflightRequests.clear();
|
||||
console.log('[CACHE] Cleared all cached feature flag requests');
|
||||
}
|
||||
```
|
||||
|
||||
**Why Sorted Keys?**
|
||||
- `{a:true, b:false}` vs `{b:false, a:true}` are semantically identical
|
||||
- Without sorting, they generate different cache keys → cache misses
|
||||
- Sorting ensures consistent key regardless of property order
|
||||
|
||||
**Why Worker Isolation?**
|
||||
- Playwright workers run in parallel across different browser contexts
|
||||
- Each worker needs its own cache to avoid state conflicts
|
||||
- Worker index provides unique namespace per parallel process
|
||||
|
||||
**Expected Impact**:
|
||||
- 30-40% reduction in duplicate API calls (revised from original 70-80% estimate)
|
||||
- Cache hit rate should be >30% based on similar flag state checks
|
||||
- Reduced API server load during parallel test execution
|
||||
|
||||
## Investigation: Fix 1.2 - DNS Provider Label Mismatches
|
||||
|
||||
**Status**: Partially Investigated
|
||||
|
||||
**Issue**:
|
||||
- Test: `tests/dns-provider-types.spec.ts` (line 260)
|
||||
- Symptom: Label locator `/script.*path/i` passes in Chromium, fails in Firefox/WebKit
|
||||
- Test code:
|
||||
```typescript
|
||||
const scriptField = page.getByLabel(/script.*path/i);
|
||||
await expect(scriptField).toBeVisible({ timeout: 10000 });
|
||||
```
|
||||
|
||||
**Investigation Steps Completed**:
|
||||
1. ✅ Confirmed E2E environment is running and healthy
|
||||
2. ✅ Attempted to run DNS provider type tests in Chromium
|
||||
3. ⏸️ Further investigation deferred due to test execution issues
|
||||
|
||||
**Investigation Steps Remaining** (per spec):
|
||||
1. Run with Playwright Inspector to compare accessibility trees:
|
||||
```bash
|
||||
npx playwright test tests/dns-provider-types.spec.ts --project=chromium --headed --debug
|
||||
npx playwright test tests/dns-provider-types.spec.ts --project=firefox --headed --debug
|
||||
```
|
||||
|
||||
2. Use `await page.getByRole('textbox').all()` to list all text inputs and their labels
|
||||
|
||||
3. Document findings in a Decision Record if labels differ
|
||||
|
||||
4. If fixable: Update component to ensure consistent aria-labels
|
||||
|
||||
5. If not fixable: Use the helper function approach from Phase 2
|
||||
|
||||
**Recommendation**:
|
||||
- Complete investigation in separate session with headed browser mode
|
||||
- DO NOT add `.or()` chains unless investigation proves it's necessary
|
||||
- Create formal Decision Record once root cause is identified
|
||||
|
||||
## Validation Checkpoints
|
||||
|
||||
### Checkpoint 1: Execution Time
|
||||
**Status**: ⏸️ In Progress
|
||||
|
||||
**Target**: <15 minutes (900s) for full test suite
|
||||
|
||||
**Command**:
|
||||
```bash
|
||||
time npx playwright test tests/settings/system-settings.spec.ts --project=chromium
|
||||
```
|
||||
|
||||
**Results**:
|
||||
- Test execution interrupted during validation
|
||||
- Observed: Tests were picking up multiple spec files from security/ folder
|
||||
- Need to investigate test file patterns or run with more specific filtering
|
||||
|
||||
**Action Required**:
|
||||
- Re-run with corrected test file path or filtering
|
||||
- Ensure only system-settings tests are executed
|
||||
- Measure execution time and compare to baseline
|
||||
|
||||
### Checkpoint 2: Test Isolation
|
||||
**Status**: ⏳ Pending
|
||||
|
||||
**Target**: All tests pass with `--repeat-each=5 --workers=4`
|
||||
|
||||
**Command**:
|
||||
```bash
|
||||
npx playwright test tests/settings/system-settings.spec.ts --project=chromium --repeat-each=5 --workers=4
|
||||
```
|
||||
|
||||
**Status**: Not executed yet
|
||||
|
||||
### Checkpoint 3: Cross-browser
|
||||
**Status**: ⏳ Pending
|
||||
|
||||
**Target**: Firefox/WebKit pass rate >85%
|
||||
|
||||
**Command**:
|
||||
```bash
|
||||
npx playwright test tests/settings/system-settings.spec.ts --project=firefox --project=webkit
|
||||
```
|
||||
|
||||
**Status**: Not executed yet
|
||||
|
||||
### Checkpoint 4: DNS provider tests (secondary issue)
|
||||
**Status**: ⏳ Pending
|
||||
|
||||
**Target**: Firefox tests pass or investigation complete
|
||||
|
||||
**Command**:
|
||||
```bash
|
||||
npx playwright test tests/dns-provider-types.spec.ts --project=firefox
|
||||
```
|
||||
|
||||
**Status**: Investigation deferred
|
||||
|
||||
## Technical Decisions
|
||||
|
||||
### Decision: Use Direct API Mutation for State Restoration
|
||||
|
||||
**Context**:
|
||||
- Tests need to restore default feature flag state after modifications
|
||||
- Original approach used polling-based verification in beforeEach
|
||||
- Alternative approaches: polling in afterEach vs direct API mutation
|
||||
|
||||
**Options Evaluated**:
|
||||
1. **Polling in afterEach** - Verify state propagated after mutation
|
||||
- Pros: Confirms state is actually restored
|
||||
- Cons: Adds 500ms-2s per test (polling overhead)
|
||||
|
||||
2. **Direct API mutation without polling** (chosen)
|
||||
- Pros: Fast, predictable, no overhead
|
||||
- Cons: Assumes API mutation is synchronous/immediate
|
||||
- Why chosen: Feature flag updates are synchronous in backend
|
||||
|
||||
**Rationale**:
|
||||
- Feature flag updates via PUT /api/v1/feature-flags are processed synchronously
|
||||
- Database write is immediate (SQLite WAL mode)
|
||||
- No async propagation delay in single-process test environment
|
||||
- Subsequent tests will verify state on first read, catching any issues
|
||||
|
||||
**Impact**:
|
||||
- Test runtime reduced by 15-60s per test file (31 tests × 500ms-2s polling)
|
||||
- Risk: If state restoration fails, next test will fail loudly (detectable)
|
||||
- Acceptable trade-off for 10-20% execution time improvement
|
||||
|
||||
**Review**: Re-evaluate if state restoration failures observed in CI
|
||||
|
||||
### Decision: Cache Key Sorting for Semantic Equality
|
||||
|
||||
**Context**:
|
||||
- Multiple tests may check the same feature flag state but with different property order
|
||||
- Without normalization, `{a:true, b:false}` and `{b:false, a:true}` generate different keys
|
||||
|
||||
**Rationale**:
|
||||
- JavaScript objects have insertion order, but semantically these are identical states
|
||||
- Sorting keys ensures cache hits for semantically identical flag states
|
||||
- Minimal performance cost (~1ms for sorting 3-5 keys)
|
||||
|
||||
**Impact**:
|
||||
- Estimated 10-15% cache hit rate improvement
|
||||
- No downside - pure optimization
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Complete Fix 1.2 Investigation**:
|
||||
- Run DNS provider tests in headed mode with Playwright Inspector
|
||||
- Document actual vs expected label structure in Firefox/WebKit
|
||||
- Create Decision Record with root cause and recommended fix
|
||||
|
||||
2. **Execute All Validation Checkpoints**:
|
||||
- Fix test file selection issue (why security tests run instead of system-settings)
|
||||
- Run all 4 checkpoints sequentially
|
||||
- Document pass/fail results with screenshots if failures occur
|
||||
|
||||
3. **Measure Impact**:
|
||||
- Baseline: Record execution time before fixes
|
||||
- Post-fix: Record execution time after fixes
|
||||
- Calculate actual time savings vs predicted 310s savings
|
||||
|
||||
4. **Update Spec**:
|
||||
- Document actual vs predicted impact
|
||||
- Adjust estimates for Phase 2 based on Sprint 1 findings
|
||||
|
||||
## Code Review Checklist
|
||||
|
||||
- [x] Fix 1.1: Remove beforeEach polling
|
||||
- [x] Fix 1.1b: Add afterEach cleanup
|
||||
- [x] Fix 1.3: Implement request coalescing
|
||||
- [x] Add cache cleanup function
|
||||
- [x] Document cache key generation logic
|
||||
- [ ] Fix 1.2: Complete investigation
|
||||
- [ ] Run all validation checkpoints
|
||||
- [ ] Update spec with actual findings
|
||||
|
||||
## References
|
||||
|
||||
- **Remediation Plan**: `docs/plans/current_spec.md`
|
||||
- **Modified Files**:
|
||||
- `tests/settings/system-settings.spec.ts`
|
||||
- `tests/utils/wait-helpers.ts`
|
||||
- **Investigation Target**: `tests/dns-provider-types.spec.ts` (line 260)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-02-02
|
||||
**Author**: GitHub Copilot (Playwright Dev Mode)
|
||||
**Status**: Sprint 1 implementation complete, validation checkpoints pending
|
||||
Reference in New Issue
Block a user