mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 04:34:44 +00:00
mcp: simplify I/O architecture and remove test harness
This commit is contained in:
@@ -4,7 +4,10 @@ const lp = @import("lightpanda");
|
||||
|
||||
const App = @import("../App.zig");
|
||||
const HttpClient = @import("../http/Client.zig");
|
||||
const testing = @import("../testing.zig");
|
||||
const protocol = @import("protocol.zig");
|
||||
const router = @import("router.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
@@ -16,16 +19,15 @@ browser: lp.Browser,
|
||||
session: *lp.Session,
|
||||
page: *lp.Page,
|
||||
|
||||
is_running: std.atomic.Value(bool) = .init(false),
|
||||
out_stream: std.fs.File,
|
||||
writer: *std.io.Writer,
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, app: *App, out_stream: std.fs.File) !*Self {
|
||||
pub fn init(allocator: std.mem.Allocator, app: *App, writer: *std.io.Writer) !*Self {
|
||||
const self = try allocator.create(Self);
|
||||
errdefer allocator.destroy(self);
|
||||
|
||||
self.allocator = allocator;
|
||||
self.app = app;
|
||||
self.out_stream = out_stream;
|
||||
self.writer = writer;
|
||||
|
||||
self.http_client = try app.http.createClient(allocator);
|
||||
errdefer self.http_client.deinit();
|
||||
@@ -43,8 +45,6 @@ pub fn init(allocator: std.mem.Allocator, app: *App, out_stream: std.fs.File) !*
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.is_running.store(false, .release);
|
||||
|
||||
self.browser.deinit();
|
||||
self.notification.deinit();
|
||||
self.http_client.deinit();
|
||||
@@ -53,11 +53,11 @@ pub fn deinit(self: *Self) void {
|
||||
}
|
||||
|
||||
pub fn sendResponse(self: *Self, response: anytype) !void {
|
||||
var aw: std.Io.Writer.Allocating = .init(self.allocator);
|
||||
var aw: std.io.Writer.Allocating = .init(self.allocator);
|
||||
defer aw.deinit();
|
||||
try std.json.Stringify.value(response, .{ .emit_null_optional_fields = false }, &aw.writer);
|
||||
try aw.writer.writeByte('\n');
|
||||
try self.out_stream.writeAll(aw.written());
|
||||
try self.writer.writeAll(aw.writer.buffered());
|
||||
}
|
||||
|
||||
pub fn sendResult(self: *Self, id: std.json.Value, result: anytype) !void {
|
||||
@@ -82,67 +82,27 @@ pub fn sendError(self: *Self, id: std.json.Value, code: protocol.ErrorCode, mess
|
||||
});
|
||||
}
|
||||
|
||||
const testing = @import("../testing.zig");
|
||||
const McpHarness = @import("testing.zig").McpHarness;
|
||||
test "MCP Integration: synchronous smoke test" {
|
||||
const allocator = testing.allocator;
|
||||
const app = testing.test_app;
|
||||
|
||||
test "MCP Integration: smoke test" {
|
||||
const harness = try McpHarness.init(testing.allocator, testing.test_app);
|
||||
defer harness.deinit();
|
||||
|
||||
harness.thread = try std.Thread.spawn(.{}, testIntegrationSmokeInternal, .{harness});
|
||||
try harness.runServer();
|
||||
}
|
||||
|
||||
fn testIntegrationSmokeInternal(harness: *McpHarness) void {
|
||||
const aa = harness.allocator;
|
||||
var arena = std.heap.ArenaAllocator.init(aa);
|
||||
defer arena.deinit();
|
||||
const allocator = arena.allocator();
|
||||
|
||||
harness.sendRequest(
|
||||
const input =
|
||||
\\{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test-client","version":"1.0.0"}}}
|
||||
) catch |err| {
|
||||
harness.test_error = err;
|
||||
return;
|
||||
};
|
||||
|
||||
const response1 = harness.readResponse(allocator) catch |err| {
|
||||
harness.test_error = err;
|
||||
return;
|
||||
};
|
||||
testing.expect(std.mem.indexOf(u8, response1, "\"id\":1") != null) catch |err| {
|
||||
harness.test_error = err;
|
||||
return;
|
||||
};
|
||||
testing.expect(std.mem.indexOf(u8, response1, "\"tools\":{}") != null) catch |err| {
|
||||
harness.test_error = err;
|
||||
return;
|
||||
};
|
||||
testing.expect(std.mem.indexOf(u8, response1, "\"resources\":{}") != null) catch |err| {
|
||||
harness.test_error = err;
|
||||
return;
|
||||
};
|
||||
|
||||
harness.sendRequest(
|
||||
\\{"jsonrpc":"2.0","id":2,"method":"tools/list"}
|
||||
) catch |err| {
|
||||
harness.test_error = err;
|
||||
return;
|
||||
};
|
||||
;
|
||||
|
||||
const response2 = harness.readResponse(allocator) catch |err| {
|
||||
harness.test_error = err;
|
||||
return;
|
||||
};
|
||||
testing.expect(std.mem.indexOf(u8, response2, "\"id\":2") != null) catch |err| {
|
||||
harness.test_error = err;
|
||||
return;
|
||||
};
|
||||
testing.expect(std.mem.indexOf(u8, response2, "\"name\":\"goto\"") != null) catch |err| {
|
||||
harness.test_error = err;
|
||||
return;
|
||||
};
|
||||
var in_reader: std.io.Reader = .fixed(input);
|
||||
var out_alloc: std.io.Writer.Allocating = .init(allocator);
|
||||
defer out_alloc.deinit();
|
||||
|
||||
harness.server.is_running.store(false, .release);
|
||||
_ = harness.client_out.writeAll("\n") catch {};
|
||||
var server: *Self = try .init(allocator, app, &out_alloc.writer);
|
||||
defer server.deinit();
|
||||
|
||||
try router.processRequests(server, &in_reader);
|
||||
|
||||
const output = out_alloc.writer.buffered();
|
||||
try testing.expect(std.mem.indexOf(u8, output, "\"id\":1") != null);
|
||||
try testing.expect(std.mem.indexOf(u8, output, "\"tools\":{}") != null);
|
||||
try testing.expect(std.mem.indexOf(u8, output, "\"id\":2") != null);
|
||||
try testing.expect(std.mem.indexOf(u8, output, "\"name\":\"goto\"") != null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user