Sprint 278: LSP Proxy Hardening (steps 1918-1922)
- LSPMessageValidator: JSON-RPC 2.0 shape validation (method, id type, params type) - LSPCapabilityNegotiator: per-source capability tracking; shouldRoute gates on declared caps - LSPRequestThrottler: per-URI/method debounce; blocks rapid didChange floods - LSPErrorRecovery: per-source health tracking; stale-cache fallback when crashed - Sprint278IntegrationSummary: poly-parse (C++ + Haskell) end-to-end integration 26/26 tests passing (5+5+5+5+6). All new headers well under 600 lines. LoRA recorded: sprint278-2026-03-01 (9 calls, 6437 tokens). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
80
editor/tests/step1920_test.cpp
Normal file
80
editor/tests/step1920_test.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
// Step 1920: LSPRequestThrottler
|
||||
// Debounces per-URI requests to prevent flooding language servers.
|
||||
//
|
||||
// t1: no prior record → shouldAllow true
|
||||
// t2: within debounce window → shouldAllow false
|
||||
// t3: after debounce window expires → shouldAllow true
|
||||
// t4: reset clears uri; resetAll clears everything
|
||||
// t5: lastTimestamp returns -1 for missing, correct value after record
|
||||
|
||||
#include "LSPRequestThrottler.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace ws = whetstone;
|
||||
|
||||
static int p=0,f=0;
|
||||
#define T(n) { std::cout<<" "<<#n<<"... "; }
|
||||
#define P() { std::cout<<"PASS\n"; ++p; }
|
||||
#define F(m) { std::cout<<"FAIL: "<<m<<"\n"; ++f; }
|
||||
#define C(c,m) if(!(c)){F(m);return;}
|
||||
|
||||
void t1(){
|
||||
T(no_prior_record_allows);
|
||||
ws::LSPRequestThrottler t;
|
||||
C(t.shouldAllow("file:///a.go","textDocument/didChange",1000,500), "no record allows");
|
||||
P();
|
||||
}
|
||||
|
||||
void t2(){
|
||||
T(within_debounce_window_blocks);
|
||||
ws::LSPRequestThrottler t;
|
||||
t.record("file:///a.go","textDocument/didChange",1000);
|
||||
// 200ms later, 500ms debounce → block
|
||||
C(!t.shouldAllow("file:///a.go","textDocument/didChange",1200,500), "within window blocked");
|
||||
// different method: not throttled
|
||||
C( t.shouldAllow("file:///a.go","textDocument/hover",1200,500), "different method allowed");
|
||||
// different uri: not throttled
|
||||
C( t.shouldAllow("file:///b.go","textDocument/didChange",1200,500), "different uri allowed");
|
||||
P();
|
||||
}
|
||||
|
||||
void t3(){
|
||||
T(after_debounce_window_allows);
|
||||
ws::LSPRequestThrottler t;
|
||||
t.record("file:///a.go","textDocument/didChange",1000);
|
||||
// exactly at boundary: 1000+500=1500 → allow (>=)
|
||||
C( t.shouldAllow("file:///a.go","textDocument/didChange",1500,500), "at boundary allowed");
|
||||
// past boundary
|
||||
C( t.shouldAllow("file:///a.go","textDocument/didChange",1600,500), "past boundary allowed");
|
||||
P();
|
||||
}
|
||||
|
||||
void t4(){
|
||||
T(reset_and_resetAll);
|
||||
ws::LSPRequestThrottler t;
|
||||
t.record("file:///a.go","textDocument/didChange",1000);
|
||||
t.record("file:///b.go","textDocument/didChange",1000);
|
||||
t.reset("file:///a.go");
|
||||
C( t.shouldAllow("file:///a.go","textDocument/didChange",1100,500), "a.go reset → allowed");
|
||||
C(!t.shouldAllow("file:///b.go","textDocument/didChange",1100,500), "b.go still throttled");
|
||||
t.resetAll();
|
||||
C( t.shouldAllow("file:///b.go","textDocument/didChange",1100,500), "b.go allowed after resetAll");
|
||||
P();
|
||||
}
|
||||
|
||||
void t5(){
|
||||
T(lastTimestamp);
|
||||
ws::LSPRequestThrottler t;
|
||||
C(t.lastTimestamp("file:///a.go","textDocument/didChange") == -1, "no record returns -1");
|
||||
t.record("file:///a.go","textDocument/didChange",9999);
|
||||
C(t.lastTimestamp("file:///a.go","textDocument/didChange") == 9999, "correct timestamp");
|
||||
C(t.lastTimestamp("file:///a.go","textDocument/hover") == -1, "different method -1");
|
||||
P();
|
||||
}
|
||||
|
||||
int main(){
|
||||
std::cout << "Step 1920: LSPRequestThrottler\n";
|
||||
t1(); t2(); t3(); t4(); t5();
|
||||
std::cout << "\n" << p << "/" << (p+f) << " passed\n";
|
||||
return f > 0 ? 1 : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user