🐛 fix(core): enforce strict LSP lifecycle
This commit is contained in:
@@ -77,10 +77,7 @@ import lsp.provider.workspace.will_delete_files;
|
||||
import lsp.provider.workspace.will_rename_files;
|
||||
import lsp.provider.workspace_symbol.resolve;
|
||||
import lsp.provider.text_document.publish_diagnostics;
|
||||
import lsp.provider.shutdown.shutdown;
|
||||
import lsp.provider.cancel_request.cancel_request;
|
||||
import lsp.provider.trace.set_trace;
|
||||
import lsp.provider.exit.exit;
|
||||
import lsp.core.dispatcher;
|
||||
import lsp.manager.manager_hub;
|
||||
import lsp.manager.symbol;
|
||||
@@ -160,13 +157,8 @@ export namespace lsp::test::provider
|
||||
static TestResult TestExecuteCommandProvider();
|
||||
static TestResult TestWillFileOperationsProviders();
|
||||
static TestResult TestWorkspaceSymbolResolveProvider();
|
||||
static TestResult TestShutdownProvider();
|
||||
static TestResult TestCancelRequestProvider();
|
||||
static TestResult TestSetTraceProvider();
|
||||
static TestResult TestExitProvider();
|
||||
};
|
||||
|
||||
int RunExitProviderChild();
|
||||
}
|
||||
|
||||
namespace lsp::test::provider
|
||||
@@ -175,13 +167,12 @@ namespace lsp::test::provider
|
||||
{
|
||||
struct ProviderEnv
|
||||
{
|
||||
std::vector<core::ServerLifecycleEvent> events;
|
||||
scheduler::async_executor::AsyncExecutor scheduler{ 1 };
|
||||
manager::ManagerHub hub{};
|
||||
core::ExecutionContext context;
|
||||
|
||||
ProviderEnv()
|
||||
: context([this](core::ServerLifecycleEvent event) { events.push_back(event); }, scheduler, hub)
|
||||
: context(scheduler, hub)
|
||||
{
|
||||
hub.Initialize();
|
||||
}
|
||||
@@ -365,10 +356,7 @@ namespace lsp::test::provider
|
||||
runner.addTest("workspace executeCommand provider", TestExecuteCommandProvider);
|
||||
runner.addTest("workspace will file operations providers", TestWillFileOperationsProviders);
|
||||
runner.addTest("workspaceSymbol/resolve provider", TestWorkspaceSymbolResolveProvider);
|
||||
runner.addTest("shutdown provider", TestShutdownProvider);
|
||||
runner.addTest("cancel request provider", TestCancelRequestProvider);
|
||||
runner.addTest("setTrace provider", TestSetTraceProvider);
|
||||
runner.addTest("exit provider", TestExitProvider);
|
||||
}
|
||||
|
||||
TestResult ProviderMiscTests::TestInitializeProvider()
|
||||
@@ -434,8 +422,6 @@ namespace lsp::test::provider
|
||||
});
|
||||
assertTrue(found_workspace, "Workspace symbols should be indexed");
|
||||
|
||||
assertTrue(!env.events.empty(), "Initialize should emit lifecycle event");
|
||||
assertTrue(env.events.back() == core::ServerLifecycleEvent::kInitialized, "Initialize should emit initialized");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2233,7 +2219,6 @@ namespace lsp::test::provider
|
||||
const auto& stored_obj = stored.Get<protocol::LSPObject>();
|
||||
assertTrue(stored_obj.contains("tsl"), "stored settings should include tsl section");
|
||||
|
||||
assertTrue(env.events.empty(), "didChangeConfiguration should not trigger lifecycle events");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2761,7 +2746,6 @@ namespace lsp::test::provider
|
||||
provider.HandleNotification(notification, env.context);
|
||||
}
|
||||
|
||||
assertTrue(env.events.empty(), "window message notifications should not trigger lifecycle events");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2781,7 +2765,6 @@ namespace lsp::test::provider
|
||||
::lsp::provider::telemetry::Event provider;
|
||||
provider.HandleNotification(notification, env.context);
|
||||
|
||||
assertTrue(env.events.empty(), "telemetry/event should not trigger lifecycle events");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2816,7 +2799,6 @@ namespace lsp::test::provider
|
||||
::lsp::provider::text_document::PublishDiagnostics provider;
|
||||
provider.HandleNotification(notification, env.context);
|
||||
|
||||
assertTrue(env.events.empty(), "publishDiagnostics should not trigger lifecycle events");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -3396,63 +3378,6 @@ namespace lsp::test::provider
|
||||
return result;
|
||||
}
|
||||
|
||||
TestResult ProviderMiscTests::TestShutdownProvider()
|
||||
{
|
||||
TestResult result{ "", true, "ok" };
|
||||
ProviderEnv env;
|
||||
|
||||
auto path = FixturePath("rename_case.tsl");
|
||||
auto content = ReadTextFile(path);
|
||||
auto uri = ToUri(path);
|
||||
OpenDocument(env.hub, uri, content, 1);
|
||||
|
||||
protocol::RequestMessage request;
|
||||
request.id = "shutdown";
|
||||
request.method = "shutdown";
|
||||
|
||||
::lsp::provider::Shutdown provider;
|
||||
auto json = provider.ProvideResponse(request, env.context);
|
||||
auto response = ParseResponse(json);
|
||||
assertTrue(!response.error.has_value(), "Shutdown should not return error");
|
||||
assertTrue(env.events.size() >= 1, "Shutdown should emit lifecycle event");
|
||||
assertTrue(env.events.back() == core::ServerLifecycleEvent::kShuttingDown, "Shutdown should emit shutting down");
|
||||
assertFalse(env.hub.documents().GetContent(uri).has_value(), "Shutdown should clear documents");
|
||||
return result;
|
||||
}
|
||||
|
||||
TestResult ProviderMiscTests::TestCancelRequestProvider()
|
||||
{
|
||||
TestResult result{ "", true, "ok" };
|
||||
ProviderEnv env;
|
||||
|
||||
std::atomic<bool> started{ false };
|
||||
env.scheduler.Submit("cancel_me", [&started](std::stop_token) -> std::optional<std::string> {
|
||||
started.store(true);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
return std::string("done");
|
||||
});
|
||||
|
||||
while (!started.load())
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
|
||||
protocol::CancelParams params;
|
||||
params.id = std::string("cancel_me");
|
||||
protocol::NotificationMessage notification;
|
||||
notification.method = "$/cancelRequest";
|
||||
notification.params = codec::ToLSPAny(params);
|
||||
|
||||
::lsp::provider::CancelRequest provider;
|
||||
provider.HandleNotification(notification, env.context);
|
||||
env.scheduler.WaitAll();
|
||||
|
||||
auto stats = env.scheduler.GetStatistics();
|
||||
assertEqual(std::size_t(1), static_cast<std::size_t>(stats.cancelled),
|
||||
"CancelRequest should mark task cancelled");
|
||||
return result;
|
||||
}
|
||||
|
||||
TestResult ProviderMiscTests::TestSetTraceProvider()
|
||||
{
|
||||
TestResult result{ "", true, "ok" };
|
||||
@@ -3484,24 +3409,4 @@ namespace lsp::test::provider
|
||||
return result;
|
||||
}
|
||||
|
||||
TestResult ProviderMiscTests::TestExitProvider()
|
||||
{
|
||||
TestResult result{ "", true, "ok" };
|
||||
auto exe = ExecutablePath();
|
||||
assertTrue(!exe.empty(), "ExecutablePath should be set");
|
||||
std::string command = "\"" + exe + "\" --exit-provider";
|
||||
int code = std::system(command.c_str());
|
||||
assertEqual(0, code, "Exit should return code 0");
|
||||
return result;
|
||||
}
|
||||
|
||||
int RunExitProviderChild()
|
||||
{
|
||||
ProviderEnv env;
|
||||
::lsp::provider::Exit provider;
|
||||
protocol::NotificationMessage notification;
|
||||
notification.method = "exit";
|
||||
provider.HandleNotification(notification, env.context);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user