zig 0.12.0: bring all of runStandaloneServer under test
This commit is contained in:
parent
1053c8f002
commit
c3e1ffc2ef
|
@ -96,6 +96,7 @@ pub fn build(b: *std.Build) !void {
|
||||||
// Creates steps for unit testing. This only builds the test executable
|
// Creates steps for unit testing. This only builds the test executable
|
||||||
// but does not run it.
|
// but does not run it.
|
||||||
const exe_tests = b.addTest(.{
|
const exe_tests = b.addTest(.{
|
||||||
|
.name = "test: as executable",
|
||||||
.root_source_file = .{ .path = "src/test.zig" },
|
.root_source_file = .{ .path = "src/test.zig" },
|
||||||
.target = b.resolveTargetQuery(t),
|
.target = b.resolveTargetQuery(t),
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
|
@ -115,6 +116,7 @@ pub fn build(b: *std.Build) !void {
|
||||||
// in the future. Scaleway, for instance, is another system that works
|
// in the future. Scaleway, for instance, is another system that works
|
||||||
// via shared library
|
// via shared library
|
||||||
const lib_tests = b.addTest(.{
|
const lib_tests = b.addTest(.{
|
||||||
|
.name = "test: as library",
|
||||||
.root_source_file = .{ .path = "src/flexilib.zig" },
|
.root_source_file = .{ .path = "src/flexilib.zig" },
|
||||||
.target = b.resolveTargetQuery(t),
|
.target = b.resolveTargetQuery(t),
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
const builtin = @import("builtin");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const build_options = @import("universal_lambda_build_options");
|
const build_options = @import("universal_lambda_build_options");
|
||||||
const flexilib = @import("flexilib-interface");
|
const flexilib = @import("flexilib-interface");
|
||||||
|
@ -46,7 +47,8 @@ fn runStandaloneServerParent(allocator: ?std.mem.Allocator, event_handler: inter
|
||||||
while (argi.next()) |a| {
|
while (argi.next()) |a| {
|
||||||
if (std.mem.eql(u8, child_arg, a)) {
|
if (std.mem.eql(u8, child_arg, a)) {
|
||||||
// This should never actually return
|
// This should never actually return
|
||||||
return try runStandaloneServer(allocator, event_handler);
|
try runStandaloneServer(allocator, event_handler, 8080); // TODO: configurable port
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
try al.append(a);
|
try al.append(a);
|
||||||
}
|
}
|
||||||
|
@ -66,27 +68,25 @@ fn runStandaloneServerParent(allocator: ?std.mem.Allocator, event_handler: inter
|
||||||
|
|
||||||
/// Will create a web server and marshall all requests back to our event handler
|
/// Will create a web server and marshall all requests back to our event handler
|
||||||
/// To keep things simple, we'll have this on a single thread, at least for now
|
/// To keep things simple, we'll have this on a single thread, at least for now
|
||||||
fn runStandaloneServer(allocator: ?std.mem.Allocator, event_handler: interface.HandlerFn) !u8 {
|
fn runStandaloneServer(allocator: ?std.mem.Allocator, event_handler: interface.HandlerFn, port: u16) !void {
|
||||||
// TODO: Get this under test. It doesn't work in zig 0.12.0
|
|
||||||
const alloc = allocator orelse std.heap.page_allocator;
|
const alloc = allocator orelse std.heap.page_allocator;
|
||||||
|
|
||||||
var arena = std.heap.ArenaAllocator.init(alloc);
|
var arena = std.heap.ArenaAllocator.init(alloc);
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
|
|
||||||
var aa = arena.allocator();
|
var aa = arena.allocator();
|
||||||
var server = std.http.Server.init(aa, .{ .reuse_address = true });
|
const address = try std.net.Address.parseIp("127.0.0.1", port);
|
||||||
defer server.deinit();
|
var net_server = try address.listen(.{ .reuse_address = true });
|
||||||
const address = try std.net.Address.parseIp("127.0.0.1", 8080); // TODO: allow config
|
const server_port = net_server.listen_address.in.getPort();
|
||||||
try server.listen(address);
|
_ = try std.fmt.bufPrint(&server_url, "http://127.0.0.1:{d}", .{server_port});
|
||||||
const server_port = server.socket.listen_address.in.getPort();
|
log.info("server listening at {s}", .{server_url});
|
||||||
var uri: ["http://127.0.0.1:99999".len]u8 = undefined;
|
if (builtin.is_test) server_ready = true;
|
||||||
_ = try std.fmt.bufPrint(&uri, "http://127.0.0.1:{d}", .{server_port});
|
|
||||||
log.info("server listening at {s}", .{uri});
|
|
||||||
|
|
||||||
// No threads, maybe later
|
// No threads, maybe later
|
||||||
//log.info("starting server thread, tid {d}", .{std.Thread.getCurrentId()});
|
//log.info("starting server thread, tid {d}", .{std.Thread.getCurrentId()});
|
||||||
while (true) {
|
while (remaining_requests == null or remaining_requests.? > 0) {
|
||||||
defer {
|
defer {
|
||||||
|
if (remaining_requests) |*r| r.* -= 1;
|
||||||
if (!arena.reset(.{ .retain_with_limit = 1024 * 1024 })) {
|
if (!arena.reset(.{ .retain_with_limit = 1024 * 1024 })) {
|
||||||
// reallocation failed, arena is degraded
|
// reallocation failed, arena is degraded
|
||||||
log.warn("Arena reset failed and is degraded. Resetting arena", .{});
|
log.warn("Arena reset failed and is degraded. Resetting arena", .{});
|
||||||
|
@ -95,19 +95,20 @@ fn runStandaloneServer(allocator: ?std.mem.Allocator, event_handler: interface.H
|
||||||
aa = arena.allocator();
|
aa = arena.allocator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const builtin = @import("builtin");
|
const supports_getrusage = builtin.os.tag != .windows and @hasDecl(std.posix.system, "rusage"); // Is Windows it?
|
||||||
const supports_getrusage = builtin.os.tag != .windows and @hasDecl(std.os.system, "rusage"); // Is Windows it?
|
var rss: if (supports_getrusage) std.posix.rusage else void = undefined;
|
||||||
var rss: if (supports_getrusage) std.os.rusage else void = undefined;
|
|
||||||
if (supports_getrusage and builtin.mode == .Debug)
|
if (supports_getrusage and builtin.mode == .Debug)
|
||||||
rss = std.os.getrusage(std.os.rusage.SELF);
|
rss = std.posix.getrusage(std.posix.rusage.SELF);
|
||||||
processRequest(aa, &server, event_handler) catch |e| {
|
if (builtin.is_test) bytes_allocated = arena.queryCapacity();
|
||||||
|
processRequest(aa, &net_server, event_handler) catch |e| {
|
||||||
log.err("Unexpected error processing request: {any}", .{e});
|
log.err("Unexpected error processing request: {any}", .{e});
|
||||||
if (@errorReturnTrace()) |trace| {
|
if (@errorReturnTrace()) |trace| {
|
||||||
std.debug.dumpStackTrace(trace.*);
|
std.debug.dumpStackTrace(trace.*);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if (builtin.is_test) bytes_allocated = arena.queryCapacity() - bytes_allocated;
|
||||||
if (supports_getrusage and builtin.mode == .Debug) { // and debug mode) {
|
if (supports_getrusage and builtin.mode == .Debug) { // and debug mode) {
|
||||||
const rusage = std.os.getrusage(std.os.rusage.SELF);
|
const rusage = std.posix.getrusage(std.posix.rusage.SELF);
|
||||||
log.debug(
|
log.debug(
|
||||||
"Request complete, max RSS of process: {d}M. Incremental: {d}K, User: {d}μs, System: {d}μs",
|
"Request complete, max RSS of process: {d}M. Incremental: {d}K, User: {d}μs, System: {d}μs",
|
||||||
.{
|
.{
|
||||||
|
@ -121,10 +122,11 @@ fn runStandaloneServer(allocator: ?std.mem.Allocator, event_handler: interface.H
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn processRequest(aa: std.mem.Allocator, server: *std.net.Server, event_handler: interface.HandlerFn) !void {
|
fn processRequest(aa: std.mem.Allocator, server: *std.net.Server, event_handler: interface.HandlerFn) !void {
|
||||||
|
// This function is under test, but not the standalone server itself
|
||||||
var connection = try server.accept();
|
var connection = try server.accept();
|
||||||
defer connection.stream.close();
|
defer connection.stream.close();
|
||||||
|
|
||||||
|
@ -189,43 +191,48 @@ test {
|
||||||
// TODO: Do we want build files here too?
|
// TODO: Do we want build files here too?
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testRequest(request_bytes: []const u8, event_handler: interface.HandlerFn) !void {
|
var server_ready = false;
|
||||||
const allocator = std.testing.allocator;
|
var remaining_requests: ?usize = null;
|
||||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
var server_url: ["http://127.0.0.1:99999".len]u8 = undefined;
|
||||||
defer arena.deinit();
|
var bytes_allocated: usize = 0;
|
||||||
|
|
||||||
const address = try std.net.Address.parseIp("127.0.0.1", 0);
|
fn testRequest(method: std.http.Method, target: []const u8, event_handler: interface.HandlerFn) !void {
|
||||||
var http_server = try address.listen(.{ .reuse_address = true });
|
remaining_requests = 1;
|
||||||
const server_port = http_server.listen_address.in.getPort();
|
defer remaining_requests = null;
|
||||||
|
|
||||||
var al = std.ArrayList(u8).init(allocator);
|
|
||||||
defer al.deinit();
|
|
||||||
const writer = al.writer();
|
|
||||||
_ = writer;
|
|
||||||
const aa = arena.allocator();
|
|
||||||
const bytes_allocated: usize = 0;
|
|
||||||
// pre-warm
|
|
||||||
const server_thread = try std.Thread.spawn(
|
const server_thread = try std.Thread.spawn(
|
||||||
.{},
|
.{},
|
||||||
processRequest,
|
runStandaloneServer,
|
||||||
.{ aa, &http_server, event_handler },
|
.{ null, event_handler, 0 },
|
||||||
);
|
);
|
||||||
|
var client = std.http.Client{ .allocator = std.testing.allocator };
|
||||||
|
defer client.deinit();
|
||||||
|
defer server_ready = false;
|
||||||
|
while (!server_ready) std.time.sleep(1);
|
||||||
|
|
||||||
const stream = try std.net.tcpConnectToHost(allocator, "127.0.0.1", server_port);
|
const url = try std.mem.concat(std.testing.allocator, u8, &[_][]const u8{ server_url[0..], target });
|
||||||
defer stream.close();
|
defer std.testing.allocator.free(url);
|
||||||
_ = try stream.writeAll(request_bytes[0..]);
|
log.debug("fetch from url: {s}", .{url});
|
||||||
|
|
||||||
|
var response_data = std.ArrayList(u8).init(std.testing.allocator);
|
||||||
|
defer response_data.deinit();
|
||||||
|
|
||||||
|
const resp = try client.fetch(.{
|
||||||
|
.response_storage = .{ .dynamic = &response_data },
|
||||||
|
.method = method,
|
||||||
|
.location = .{ .url = url },
|
||||||
|
});
|
||||||
|
|
||||||
server_thread.join();
|
server_thread.join();
|
||||||
log.debug("Bytes allocated during request: {d}", .{arena.queryCapacity() - bytes_allocated});
|
log.debug("Bytes allocated during request: {d}", .{bytes_allocated});
|
||||||
log.debug("Stdout: {s}", .{al.items});
|
log.debug("Response status: {}", .{resp.status});
|
||||||
|
log.debug("Response: {s}", .{response_data.items});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testGet(comptime path: []const u8, event_handler: interface.HandlerFn) !void {
|
fn testGet(comptime path: []const u8, event_handler: interface.HandlerFn) !void {
|
||||||
try testRequest("GET " ++ path ++ " HTTP/1.1\r\n" ++
|
try testRequest(.GET, path, event_handler);
|
||||||
"Accept: */*\r\n" ++
|
|
||||||
"\r\n", event_handler);
|
|
||||||
}
|
}
|
||||||
test "can make a request" {
|
test "can make a request" {
|
||||||
|
// std.testing.log_level = .debug;
|
||||||
if (@import("builtin").os.tag == .wasi) return error.SkipZigTest;
|
if (@import("builtin").os.tag == .wasi) return error.SkipZigTest;
|
||||||
const HandlerClosure = struct {
|
const HandlerClosure = struct {
|
||||||
var data_received: []const u8 = undefined;
|
var data_received: []const u8 = undefined;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user