127 lines
3.6 KiB
Zig
127 lines
3.6 KiB
Zig
const std = @import("std");
|
|
const zap = @import("zap");
|
|
const zouter = @import("zouter");
|
|
|
|
/// Stop zap in 3s.
|
|
fn stopAfter3s() !void {
|
|
std.time.sleep(3 * std.time.ns_per_s);
|
|
zap.stop();
|
|
}
|
|
|
|
// Spawn a new thread to stop zap in 3s.
|
|
fn stopAfter3sThread() !std.Thread {
|
|
return try std.Thread.spawn(.{}, stopAfter3s, .{});
|
|
}
|
|
|
|
// Make an HTTP request to the given URL and put the result in the given pointed variable.
|
|
fn makeRequest(allocator: std.mem.Allocator, method: std.http.Method, url: []const u8, varPointer: *[]const u8) !void {
|
|
// Emit HTTP request to the server.
|
|
var http_client: std.http.Client = .{ .allocator = allocator };
|
|
defer http_client.deinit();
|
|
var response = std.ArrayList(u8).init(allocator);
|
|
defer response.deinit();
|
|
_ = try http_client.fetch(.{
|
|
.method = method,
|
|
.location = .{ .url = url },
|
|
.response_storage = .{ .dynamic = &response },
|
|
});
|
|
|
|
varPointer.* = try allocator.dupe(u8, response.items);
|
|
}
|
|
|
|
/// Make a request thread.
|
|
fn makeRequestThread(allocator: std.mem.Allocator, method: std.http.Method, url: []const u8, varPointer: *[]const u8) !std.Thread {
|
|
return try std.Thread.spawn(.{}, makeRequest, .{ allocator, method, url, varPointer });
|
|
}
|
|
|
|
/// GET /foo/:arg/bar request handler.
|
|
fn get(route: zouter.MatchedRoute, request: zap.Request) !void {
|
|
var bodyBuffer: [512]u8 = undefined;
|
|
const body = try std.fmt.bufPrint(&bodyBuffer, "get: {s}", .{route.params.get("arg").?});
|
|
try request.sendBody(body);
|
|
}
|
|
|
|
/// POST /foo/:arg/bar request handler.
|
|
fn post(route: zouter.MatchedRoute, request: zap.Request) !void {
|
|
var bodyBuffer: [512]u8 = undefined;
|
|
const body = try std.fmt.bufPrint(&bodyBuffer, "post: {s}", .{route.params.get("arg").?});
|
|
try request.sendBody(body);
|
|
}
|
|
|
|
/// Setup an example router.
|
|
fn setupExampleRouter(allocator: std.mem.Allocator) !zouter.Router {
|
|
// Initialize an example router.
|
|
var exampleRouter = try zouter.Router.init(allocator, .{});
|
|
|
|
// Add a route to the example router.
|
|
try exampleRouter.route(.{
|
|
.path = "foo",
|
|
.children = &[_]zouter.RouteDefinition{
|
|
.{
|
|
.path = ":arg",
|
|
.children = &[_]zouter.RouteDefinition{
|
|
.{
|
|
.path = "bar",
|
|
.handle = .{
|
|
.get = &get,
|
|
.post = &post,
|
|
},
|
|
}
|
|
},
|
|
}
|
|
},
|
|
});
|
|
|
|
return exampleRouter;
|
|
}
|
|
|
|
/// Run HTTP server with test router.
|
|
fn runHttp(allocator: std.mem.Allocator) !void {
|
|
// Setup test router.
|
|
var exampleRouter = try setupExampleRouter(allocator);
|
|
defer exampleRouter.deinit();
|
|
|
|
// Setup HTTP listener.
|
|
var listener = zap.HttpListener.init(.{
|
|
.interface = "127.0.0.1",
|
|
.port = 8112,
|
|
.log = true,
|
|
// Add zouter to the listener.
|
|
.on_request = zouter.Router.onRequest,
|
|
});
|
|
try listener.listen();
|
|
|
|
// Emit a GET HTTP request.
|
|
const getThread = try makeRequestThread(allocator, std.http.Method.GET, "http://127.0.0.1:8112/foo/any%20value/bar", &getResponse);
|
|
defer getThread.join();
|
|
|
|
// Emit a POST HTTP request.
|
|
const postThread = try makeRequestThread(allocator, std.http.Method.POST, "http://127.0.0.1:8112/foo/any%20value/bar", &postResponse);
|
|
defer postThread.join();
|
|
|
|
// Add zap stop in 3s.
|
|
const stopThread = try stopAfter3sThread();
|
|
defer stopThread.join();
|
|
|
|
// Start HTTP server workers.
|
|
zap.start(.{
|
|
.threads = 1,
|
|
.workers = 1,
|
|
});
|
|
}
|
|
|
|
var getResponse: []const u8 = undefined;
|
|
var postResponse: []const u8 = undefined;
|
|
|
|
test {
|
|
const allocator = std.testing.allocator;
|
|
try runHttp(allocator);
|
|
|
|
// Test that responses are correct.
|
|
try std.testing.expectEqualStrings("get: any value", getResponse);
|
|
try std.testing.expectEqualStrings("post: any value", postResponse);
|
|
|
|
// Free allocated responses.
|
|
allocator.free(getResponse);
|
|
allocator.free(postResponse);
|
|
}
|