181 lines
5.2 KiB
Zig
181 lines
5.2 KiB
Zig
const std = @import("std");
|
|
const zap = @import("zap");
|
|
const zouter = @import("zouter");
|
|
|
|
var notFoundResponse: []const u8 = undefined;
|
|
var errorResponse: []const u8 = undefined;
|
|
var customErrorResponse: []const u8 = undefined;
|
|
var customNotFoundResponse: []const u8 = undefined;
|
|
var okResponse: []const u8 = undefined;
|
|
var argTestResponse: []const u8 = undefined;
|
|
|
|
fn stopAfter3s() !void {
|
|
std.time.sleep(3 * std.time.ns_per_s);
|
|
zap.stop();
|
|
}
|
|
|
|
fn stopAfter3sThread() !std.Thread {
|
|
return try std.Thread.spawn(.{}, stopAfter3s, .{});
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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 });
|
|
}
|
|
|
|
fn notFoundHandler(_: zouter.MatchedRoute, request: zap.Request) !void
|
|
{
|
|
try request.sendBody("not found");
|
|
}
|
|
|
|
fn internalErrorHandler(_: zouter.MatchedRoute, request: zap.Request, _: anyerror) !void
|
|
{
|
|
try request.sendBody("error!");
|
|
}
|
|
|
|
fn customNotFound(_: zouter.MatchedRoute, request: zap.Request) !void
|
|
{
|
|
try request.sendBody("sorry, this page does not exists...");
|
|
}
|
|
|
|
fn customErrorHandler(_: zouter.MatchedRoute, request: zap.Request, _: anyerror) !void
|
|
{
|
|
try request.sendBody("custom error!");
|
|
}
|
|
|
|
fn empty(_: zouter.MatchedRoute, _: zap.Request) !void
|
|
{
|
|
unreachable;
|
|
}
|
|
|
|
fn ok(_: zouter.MatchedRoute, request: zap.Request) !void
|
|
{
|
|
try request.sendBody("ok");
|
|
}
|
|
|
|
fn sendArgTest(route: zouter.MatchedRoute, request: zap.Request) !void
|
|
{
|
|
try request.sendBody(route.params.get("argTest").?);
|
|
}
|
|
|
|
fn badlyMadeHandler(_: zouter.MatchedRoute, _: zap.Request) !void
|
|
{
|
|
return error.HttpParseBody;
|
|
}
|
|
|
|
/// Setup test router.
|
|
fn setupTestRouter(allocator: std.mem.Allocator) !zouter.Router {
|
|
var testRouter = try zouter.Router.init(allocator, .{
|
|
.handleNotFound = ¬FoundHandler,
|
|
.handleError = &internalErrorHandler,
|
|
});
|
|
|
|
try testRouter.route(.{
|
|
.path = "anything",
|
|
.children = &[_]zouter.RouteDefinition{
|
|
.{
|
|
.path = ":argTest",
|
|
.children = &[_]zouter.RouteDefinition{
|
|
.{
|
|
.path = "test",
|
|
.handle = .{
|
|
.get = &badlyMadeHandler,
|
|
.delete = &ok,
|
|
.patch = &sendArgTest,
|
|
},
|
|
}
|
|
},
|
|
}
|
|
},
|
|
.handleError = &customErrorHandler,
|
|
.handleNotFound = &customNotFound,
|
|
});
|
|
|
|
try testRouter.route(.{
|
|
.path = "error",
|
|
.handle = .{
|
|
.any = &badlyMadeHandler,
|
|
},
|
|
});
|
|
|
|
return testRouter;
|
|
}
|
|
|
|
/// Run HTTP server with test router.
|
|
fn runHttp() !void {
|
|
const allocator = std.testing.allocator;
|
|
|
|
// Setup test router.
|
|
var testRouter = try setupTestRouter(allocator);
|
|
defer testRouter.deinit();
|
|
|
|
// Setup HTTP listener.
|
|
var listener = zap.HttpListener.init(.{
|
|
.interface = "127.0.0.1",
|
|
.port = 8112,
|
|
.log = false,
|
|
// Add zouter to the listener.
|
|
.on_request = zouter.Router.onRequest,
|
|
});
|
|
zap.enableDebugLog();
|
|
try listener.listen();
|
|
|
|
const notFoundThread = try makeRequestThread(allocator, std.http.Method.GET, "http://127.0.0.1:8112/notfound/query", ¬FoundResponse);
|
|
defer notFoundThread.join();
|
|
|
|
const errorThread = try makeRequestThread(allocator, std.http.Method.GET, "http://127.0.0.1:8112/error", &errorResponse);
|
|
defer errorThread.join();
|
|
|
|
const customErrorThread = try makeRequestThread(allocator, std.http.Method.GET, "http://127.0.0.1:8112/anything/test%20val/test", &customErrorResponse);
|
|
defer customErrorThread.join();
|
|
|
|
const customNotFoundThread = try makeRequestThread(allocator, std.http.Method.POST, "http://127.0.0.1:8112/anything/test%20val/test", &customNotFoundResponse);
|
|
defer customNotFoundThread.join();
|
|
|
|
const okThread = try makeRequestThread(allocator, std.http.Method.DELETE, "http://127.0.0.1:8112/anything/test%20val/test", &okResponse);
|
|
defer okThread.join();
|
|
|
|
const argTestThread = try makeRequestThread(allocator, std.http.Method.PATCH, "http://127.0.0.1:8112/anything/test%20val/test", &argTestResponse);
|
|
defer argTestThread.join();
|
|
|
|
const stopThread = try stopAfter3sThread();
|
|
defer stopThread.join();
|
|
|
|
// Start HTTP server workers.
|
|
zap.start(.{
|
|
.threads = 1,
|
|
.workers = 1,
|
|
});
|
|
}
|
|
|
|
test {
|
|
try runHttp();
|
|
|
|
try std.testing.expectEqualStrings("not found", notFoundResponse);
|
|
try std.testing.expectEqualStrings("error!", errorResponse);
|
|
try std.testing.expectEqualStrings("custom error!", customErrorResponse);
|
|
try std.testing.expectEqualStrings("sorry, this page does not exists...", customNotFoundResponse);
|
|
try std.testing.expectEqualStrings("ok", okResponse);
|
|
try std.testing.expectEqualStrings("test val", argTestResponse);
|
|
|
|
std.testing.allocator.free(notFoundResponse);
|
|
std.testing.allocator.free(errorResponse);
|
|
std.testing.allocator.free(customErrorResponse);
|
|
std.testing.allocator.free(customNotFoundResponse);
|
|
std.testing.allocator.free(okResponse);
|
|
std.testing.allocator.free(argTestResponse);
|
|
}
|