diff --git a/src/app.zig b/src/app.zig index 1ba6e234..ee690e73 100644 --- a/src/app.zig +++ b/src/app.zig @@ -14,7 +14,7 @@ const Notification = @import("notification.zig").Notification; pub const App = struct { http: Http, config: Config, - platform: ?*const Platform, + platform: Platform, allocator: Allocator, telemetry: Telemetry, app_dir_path: ?[]const u8, @@ -29,7 +29,6 @@ pub const App = struct { pub const Config = struct { run_mode: RunMode, - platform: ?*const Platform = null, tls_verify_host: bool = true, http_proxy: ?[:0]const u8 = null, proxy_bearer_token: ?[:0]const u8 = null, @@ -57,13 +56,16 @@ pub const App = struct { }); errdefer http.deinit(); + const platform = try Platform.init(); + errdefer platform.deinit(); + const app_dir_path = getAndMakeAppDir(allocator); app.* = .{ .http = http, .allocator = allocator, .telemetry = undefined, - .platform = config.platform, + .platform = platform, .app_dir_path = app_dir_path, .notification = notification, .config = config, @@ -85,6 +87,7 @@ pub const App = struct { self.telemetry.deinit(); self.notification.deinit(); self.http.deinit(); + self.platform.deinit(); allocator.destroy(self); } }; diff --git a/src/browser/browser.zig b/src/browser/browser.zig index 1b5636e9..26687c53 100644 --- a/src/browser/browser.zig +++ b/src/browser/browser.zig @@ -48,7 +48,7 @@ pub const Browser = struct { pub fn init(app: *App) !Browser { const allocator = app.allocator; - const env = try Env.init(allocator, app.platform, .{}); + const env = try Env.init(allocator, &app.platform, .{}); errdefer env.deinit(); const notification = try Notification.init(allocator, app.notification); diff --git a/src/browser/html/elements.zig b/src/browser/html/elements.zig index 4799ea76..3a735dd7 100644 --- a/src/browser/html/elements.zig +++ b/src/browser/html/elements.zig @@ -1347,7 +1347,7 @@ test "Browser.HTML.Element.DataSet" { test "Browser.HTML.HtmlInputElement.properties" { var runner = try testing.jsRunner(testing.tracking_allocator, .{ .url = "https://lightpanda.io/noslashattheend" }); defer runner.deinit(); - var alloc = std.heap.ArenaAllocator.init(runner.app.allocator); + var alloc = std.heap.ArenaAllocator.init(runner.allocator); defer alloc.deinit(); const arena = alloc.allocator(); diff --git a/src/cdp/testing.zig b/src/cdp/testing.zig index 28db67e7..c6076c4e 100644 --- a/src/cdp/testing.zig +++ b/src/cdp/testing.zig @@ -71,7 +71,6 @@ const TestCDP = main.CDPT(struct { }); const TestContext = struct { - app: *App, client: ?Client = null, cdp_: ?TestCDP = null, arena: ArenaAllocator, @@ -80,7 +79,6 @@ const TestContext = struct { if (self.cdp_) |*c| { c.deinit(); } - self.app.deinit(); self.arena.deinit(); } @@ -89,7 +87,7 @@ const TestContext = struct { self.client = Client.init(self.arena.allocator()); // Don't use the arena here. We want to detect leaks in CDP. // The arena is only for test-specific stuff - self.cdp_ = TestCDP.init(self.app, &self.client.?) catch unreachable; + self.cdp_ = TestCDP.init(base.test_app, &self.client.?) catch unreachable; } return &self.cdp_.?; } @@ -221,7 +219,6 @@ const TestContext = struct { pub fn context() TestContext { return .{ - .app = App.init(std.testing.allocator, .{ .run_mode = .serve }) catch unreachable, .arena = ArenaAllocator.init(std.testing.allocator), }; } diff --git a/src/main.zig b/src/main.zig index 3e6af90f..f4f0a247 100644 --- a/src/main.zig +++ b/src/main.zig @@ -22,9 +22,8 @@ const Allocator = std.mem.Allocator; const log = @import("log.zig"); const App = @import("app.zig").App; -const Server = @import("server.zig").Server; const Http = @import("http/Http.zig"); -const Platform = @import("runtime/js.zig").Platform; +const Server = @import("server.zig").Server; const Browser = @import("browser/browser.zig").Browser; const build_config = @import("build_config"); @@ -109,13 +108,9 @@ fn run(alloc: Allocator) !void { log.opts.filter_scopes = lfs; } - const platform = try Platform.init(); - defer platform.deinit(); - // _app is global to handle graceful shutdown. _app = try App.init(alloc, .{ .run_mode = args.mode, - .platform = &platform, .http_proxy = args.httpProxy(), .proxy_bearer_token = args.proxyBearerToken(), .tls_verify_host = args.tlsVerifyHost(), @@ -124,6 +119,7 @@ fn run(alloc: Allocator) !void { .http_max_host_open = args.httpMaxHostOpen(), .http_max_concurrent = args.httpMaxConcurrent(), }); + const app = _app.?; defer app.deinit(); app.telemetry.record(.{ .run = {} }); @@ -715,48 +711,50 @@ fn parseCommonArg( return false; } +const testing = @import("testing.zig"); test { std.testing.refAllDecls(@This()); } -var test_wg: std.Thread.WaitGroup = .{}; +var test_cdp_server: ?Server = null; test "tests:beforeAll" { - try parser.init(); log.opts.level = .err; log.opts.format = .logfmt; - test_wg.startMany(2); - const platform = try Platform.init(); + try testing.setup(); + + var wg: std.Thread.WaitGroup = .{}; + wg.startMany(2); { - const address = try std.net.Address.parseIp("127.0.0.1", 9582); - const thread = try std.Thread.spawn(.{}, serveHTTP, .{address}); + const thread = try std.Thread.spawn(.{}, serveHTTP, .{&wg}); thread.detach(); } { - const address = try std.net.Address.parseIp("127.0.0.1", 9583); - const thread = try std.Thread.spawn(.{}, serveCDP, .{ address, &platform }); + const thread = try std.Thread.spawn(.{}, serveCDP, .{&wg}); thread.detach(); } // need to wait for the servers to be listening, else tests will fail because // they aren't able to connect. - test_wg.wait(); + wg.wait(); } test "tests:afterAll" { - parser.deinit(); + if (test_cdp_server) |*server| { + server.deinit(); + } + testing.shutdown(); } -fn serveHTTP(address: std.net.Address) !void { - var arena = std.heap.ArenaAllocator.init(std.testing.allocator); - defer arena.deinit(); +fn serveHTTP(wg: *std.Thread.WaitGroup) !void { + const address = try std.net.Address.parseIp("127.0.0.1", 9582); var listener = try address.listen(.{ .reuse_address = true }); defer listener.deinit(); - test_wg.finish(); + wg.finish(); var read_buffer: [1024]u8 = undefined; while (true) { @@ -799,20 +797,15 @@ fn serveHTTP(address: std.net.Address) !void { } } -fn serveCDP(address: std.net.Address, platform: *const Platform) !void { - var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init; - var app = try App.init(gpa.allocator(), .{ - .run_mode = .serve, - .tls_verify_host = false, - .platform = platform, - .http_max_concurrent = 2, - }); - defer app.deinit(); +fn serveCDP(wg: *std.Thread.WaitGroup) !void { + const address = try std.net.Address.parseIp("127.0.0.1", 9583); + test_cdp_server = try Server.init(testing.test_app, address); - test_wg.finish(); - var server = try Server.init(app, address); + var server = try Server.init(testing.test_app, address); defer server.deinit(); - server.run(address, 5) catch |err| { + wg.finish(); + + test_cdp_server.?.run(address, 5) catch |err| { std.debug.print("CDP server error: {}", .{err}); return err; }; diff --git a/src/main_wpt.zig b/src/main_wpt.zig index 4ebbe3ab..d3741f80 100644 --- a/src/main_wpt.zig +++ b/src/main_wpt.zig @@ -48,8 +48,8 @@ pub fn main() !void { const cmd = try parseArgs(runner_arena); - const platform = try Platform.init(); - defer platform.deinit(); + try @import("testing.zig").setup(); + defer @import("testing.zig").shutdown(); // prepare libraries to load on each test case. var loader = FileLoader.init(runner_arena, WPT_DIR); @@ -69,7 +69,6 @@ pub fn main() !void { var err_out: ?[]const u8 = null; const result = run( test_arena.allocator(), - &platform, test_file, &loader, &err_out, @@ -81,12 +80,11 @@ pub fn main() !void { }; if (result == null and err_out == null) { - // We somtimes pass a non-test to `run` (we don't know it's a non + // We sometimes pass a non-test to `run` (we don't know it's a non // test, we need to open the contents of the test file to find out // and that's in run). continue; } - try writer.process(test_file, result, err_out); } try writer.finalize(); @@ -94,7 +92,6 @@ pub fn main() !void { fn run( arena: Allocator, - platform: *const Platform, test_file: []const u8, loader: *FileLoader, err_out: *?[]const u8, @@ -119,10 +116,15 @@ fn run( var runner = try @import("testing.zig").jsRunner(arena, .{ .url = "http://127.0.0.1", .html = html, - .platform = platform, }); defer runner.deinit(); + defer if (err_out.*) |eo| { + // the error might be owned by the runner, we'll dupe it with our + // own arena so that it can be returned out of this function. + err_out.* = arena.dupe(u8, eo) catch "failed to dupe error"; + }; + try polyfill.preload(arena, runner.page.main_context); // loop over the scripts. @@ -179,6 +181,7 @@ fn run( // return the detailed result. const res = try runner.eval("report.log", "report", err_out); + return try res.toString(arena); } diff --git a/src/runtime/js.zig b/src/runtime/js.zig index 3e1ad2e8..da7e459d 100644 --- a/src/runtime/js.zig +++ b/src/runtime/js.zig @@ -153,7 +153,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { return struct { allocator: Allocator, - platform: ?*const Platform, + platform: *const Platform, // the global isolate isolate: v8.Isolate, @@ -182,7 +182,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { const Opts = struct {}; - pub fn init(allocator: Allocator, platform: ?*const Platform, _: Opts) !*Self { + pub fn init(allocator: Allocator, platform: *const Platform, _: Opts) !*Self { // var params = v8.initCreateParams(); var params = try allocator.create(v8.CreateParams); errdefer allocator.destroy(params); @@ -301,13 +301,11 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { } pub fn pumpMessageLoop(self: *const Self) bool { - // assume it's not-null. - return self.platform.?.inner.pumpMessageLoop(self.isolate, false); + return self.platform.inner.pumpMessageLoop(self.isolate, false); } pub fn runIdleTasks(self: *const Self) void { - // assume it's not-null. - return self.platform.?.inner.runIdleTasks(self.isolate, 1); + return self.platform.inner.runIdleTasks(self.isolate, 1); } pub fn newExecutionWorld(self: *Self) !ExecutionWorld { diff --git a/src/runtime/testing.zig b/src/runtime/testing.zig index 87246d8e..82327919 100644 --- a/src/runtime/testing.zig +++ b/src/runtime/testing.zig @@ -18,6 +18,7 @@ const std = @import("std"); const js = @import("js.zig"); +const base = @import("../testing.zig"); const generate = @import("generate.zig"); pub const allocator = std.testing.allocator; @@ -42,7 +43,7 @@ pub fn Runner(comptime State: type, comptime Global: type, comptime types: anyty const self = try allocator.create(Self); errdefer allocator.destroy(self); - self.env = try Env.init(allocator, null, .{}); + self.env = try Env.init(allocator, &base.test_app.platform, .{}); errdefer self.env.deinit(); self.executor = try self.env.newExecutionWorld(); diff --git a/src/telemetry/telemetry.zig b/src/telemetry/telemetry.zig index 709898c0..d9e8c304 100644 --- a/src/telemetry/telemetry.zig +++ b/src/telemetry/telemetry.zig @@ -186,10 +186,7 @@ test "telemetry: getOrCreateId" { } test "telemetry: sends event to provider" { - var app = testing.createApp(.{}); - defer app.deinit(); - - var telemetry = try TelemetryT(MockProvider).init(app, .serve); + var telemetry = try TelemetryT(MockProvider).init(testing.test_app, .serve); defer telemetry.deinit(); const mock = &telemetry.provider; diff --git a/src/testing.zig b/src/testing.zig index 59dd8887..7287c5cd 100644 --- a/src/testing.zig +++ b/src/testing.zig @@ -175,11 +175,6 @@ pub fn print(comptime fmt: []const u8, args: anytype) void { } } -// dummy opts incase we want to add something, and not have to break all the callers -pub fn createApp(_: anytype) *App { - return App.init(allocator, .{ .run_mode = .serve }) catch unreachable; -} - pub const Random = struct { var instance: ?std.Random.DefaultPrng = null; @@ -375,24 +370,17 @@ pub const JsRunner = struct { const Page = @import("browser/page.zig").Page; const Browser = @import("browser/browser.zig").Browser; - app: *App, page: *Page, browser: *Browser, + allocator: Allocator, fn init(alloc: Allocator, opts: RunnerOpts) !JsRunner { parser.deinit(); - var app = try App.init(alloc, .{ - .run_mode = .serve, - .tls_verify_host = false, - .platform = opts.platform, - }); - errdefer app.deinit(); - const browser = try alloc.create(Browser); errdefer alloc.destroy(browser); - browser.* = try Browser.init(app); + browser.* = try Browser.init(test_app); errdefer browser.deinit(); var session = try browser.newSession(); @@ -411,16 +399,15 @@ pub const JsRunner = struct { page.mode = .{ .parsed = {} }; return .{ - .app = app, .page = page, .browser = browser, + .allocator = alloc, }; } pub fn deinit(self: *JsRunner) void { self.browser.deinit(); - self.app.allocator.destroy(self.browser); - self.app.deinit(); + self.allocator.destroy(self.browser); } const RunOpts = struct {}; @@ -484,7 +471,6 @@ pub const JsRunner = struct { }; const RunnerOpts = struct { - platform: ?*const Platform = null, url: []const u8 = "https://lightpanda.io/opensource-browser/", html: []const u8 = \\
@@ -502,3 +488,19 @@ const RunnerOpts = struct { pub fn jsRunner(alloc: Allocator, opts: RunnerOpts) !JsRunner { return JsRunner.init(alloc, opts); } + +var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init; +pub var test_app: *App = undefined; + +pub fn setup() !void { + try parser.init(); + + test_app = try App.init(gpa.allocator(), .{ + .run_mode = .serve, + .tls_verify_host = false, + }); +} +pub fn shutdown() void { + parser.deinit(); + test_app.deinit(); +}