From cb903b46754916c46665678021c97fddc3a4532b Mon Sep 17 00:00:00 2001 From: dormando Date: Thu, 4 Apr 2024 15:45:46 -0700 Subject: [PATCH] write tests, fix bugs, repeat. --- proxy_luafgen.c | 4 +- t/proxyrctxtimeout.lua | 83 ++++++++++++++++++++++++++++++++++++++++++ t/proxyrctxtimeout.t | 61 +++++++++++++++++++++++++++++-- 3 files changed, 143 insertions(+), 5 deletions(-) diff --git a/proxy_luafgen.c b/proxy_luafgen.c index f495830561..1f8f1b07ce 100644 --- a/proxy_luafgen.c +++ b/proxy_luafgen.c @@ -1146,7 +1146,7 @@ void mcp_run_rcontext_handle(mcp_rcontext_t *rctx, int handle) { static inline void _mcplib_set_rctx_alarm(lua_State *L, mcp_rcontext_t *rctx, int arg) { int isnum = 0; // TODO: keep this float conversion or milliseconds directly? - lua_Number secondsf = lua_tonumberx(L, 4, &isnum); + lua_Number secondsf = lua_tonumberx(L, arg, &isnum); if (!isnum) { proxy_lua_error(L, "timeout argument to wait_cond must be a number"); return; @@ -1249,7 +1249,7 @@ int mcplib_rcontext_enqueue_and_wait(lua_State *L) { } if (!isnum) { - proxy_lua_error(L, "invalid handle passed to wait_handle"); + proxy_lua_error(L, "invalid handle passed to enqueue_and_wait"); return 0; } diff --git a/t/proxyrctxtimeout.lua b/t/proxyrctxtimeout.lua index f738c49e79..3d53b1ca90 100644 --- a/t/proxyrctxtimeout.lua +++ b/t/proxyrctxtimeout.lua @@ -41,11 +41,94 @@ function cond_timeout(p) return fgen end +function enqueue_timeout(p) + local fgen = mcp.funcgen_new() + local near = fgen:new_handle(p.z1) + local far = { fgen:new_handle(p.z2), + fgen:new_handle(p.z3) } + + local all = { near, far[1], far[2] } + fgen:ready({ n = "enqueue_timeout", f = function(rctx) + return function(r) + local nres, timeout = rctx:enqueue_and_wait(r, near, 0.5) + + if timeout then + rctx:enqueue(r, far) + local done = rctx:wait_cond(1, mcp.WAIT_GOOD) + for x=1,#all do + local res = rctx:res_any(all[x]) + if res then + return res + end + end + return "SERVER_ERROR no responses\r\n" + else + return nres + end + end + end}) + return fgen +end + +function wait_handle_timeout(p) + local fgen = mcp.funcgen_new() + local near = fgen:new_handle(p.z1) + local far = { fgen:new_handle(p.z2), + fgen:new_handle(p.z3) } + + local all = { near, far[1], far[2] } + fgen:ready({ n = "handle_timeout", f = function(rctx) + return function(r) + rctx:enqueue(r, near) + local nres, timeout = rctx:wait_handle(near, 0.5) + + if timeout then + rctx:enqueue(r, far) + local done = rctx:wait_cond(1, mcp.WAIT_GOOD) + for x=1,#all do + local res = rctx:res_any(all[x]) + if res then + return res + end + end + return "SERVER_ERROR no responses\r\n" + else + return nres + end + end + end}) + return fgen +end + +function wait_more(p) + local fgen = mcp.funcgen_new() + local near = fgen:new_handle(p.z1) + + fgen:ready({ n = "wait_more", f = function(rctx) + return function(r) + rctx:enqueue(r, near) + local nres, timeout = rctx:wait_handle(near, 0.25) + + -- wait on the same handle twice. + if timeout then + local xres = rctx:wait_handle(near) + return xres + else + return "SERVER_ERROR no timeout\r\n" + end + end + end}) + return fgen +end + -- TODO: different cond_timeout test with 2/3 instead of 1 function mcp_config_routes(p) local map = { ["cond_timeout"] = cond_timeout(p), + ["enqueue_timeout"] = enqueue_timeout(p), + ["handle_timeout"] = wait_handle_timeout(p), + ["wait_more"] = wait_more(p), } -- defaults are fine. "prefix/etc" diff --git a/t/proxyrctxtimeout.t b/t/proxyrctxtimeout.t index e99e22e125..012296de56 100644 --- a/t/proxyrctxtimeout.t +++ b/t/proxyrctxtimeout.t @@ -27,20 +27,75 @@ $ps->autoflush(1); $t->set_c($ps); $t->accept_backends(); -subtest 'cond_timeout' => sub { +subtest 'no timeout' => sub { # first response is good $t->c_send("mg cond_timeout/foo\r\n"); $t->be_recv_c(0); $t->be_send(0, "HD\r\n"); $t->c_recv_be(); $t->clear(); +}; - # first response times out. +subtest 'first req times out' => sub { $t->c_send("mg cond_timeout/boo t\r\n"); $t->be_recv_c([1,2], "far backends received requests"); + $t->be_recv_c(0, "near req still arrived"); $t->be_send([1,2], "HD t90\r\n"); - # This should delay, then complete. $t->c_recv_be(); + # Should get eaten. + $t->be_send(0, "HD t40\r\n"); + $t->clear(); +}; + +subtest 'first req times out, but still returns' => sub { + $t->c_send("mg cond_timeout/qoo t\r\n"); + $t->be_recv_c([1,2], "near timeout, far received req"); + $t->be_recv_c(0, "near received request"); + + $t->be_send(0, "HD t14\r\n"); + $t->c_recv_be("near timed out but client got its response"); + # returned but doesn't go anywhere. + $t->be_send([1,2], "HD t17\r\n"); + $t->clear(); +}; + +subtest 'enqueue_timeout' => sub { + $t->c_send("mg enqueue_timeout/foo t\r\n"); + $t->be_recv_c([1,2], "near timeout, far received req"); + $t->be_recv_c(0, "near req still arrived"); + $t->be_send([1,2], "HD t91\r\n"); + $t->c_recv_be(); + $t->be_send(0, "HD t15\r\n"); + $t->clear(); +}; + +subtest 'handle_timeout' => sub { + $t->c_send("mg handle_timeout/foo t\r\n"); + $t->be_recv_c([1,2], "near timeout, far received req"); + $t->be_recv_c(0, "near req still arrived"); + $t->be_send([1,2], "HD t92\r\n"); + $t->c_recv_be(); + $t->be_send(0, "HD t16\r\n"); + $t->clear(); +}; + +subtest 'wait on the same handle twice' => sub { + $t->c_send("mg wait_more/foo t\r\n"); + $t->be_recv_c(0, "near got request"); + # Let it internally time out. + sleep 0.75; + pass("short sleep"); + $t->be_send(0, "HD t93\r\n"); + $t->c_recv_be(); + $t->clear(); +}; + +subtest 'wait handle no timeout' => sub { + $t->c_send("mg wait_more/foo t\r\n"); + $t->be_recv_c(0, "near got request"); + $t->be_send(0, "HD t93\r\n"); + $t->c_recv("SERVER_ERROR no timeout\r\n", "client received SERVER_ERROR"); + $t->clear(); }; done_testing();