123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803 |
- local socket = require"socket"
- host = host or "localhost"
- port = port or "8383"
- function printf(...)
- io.stderr:write(string.format(...))
- end
- function pass(...)
- printf(...)
- io.stderr:write("\n")
- end
- function fail(...)
- io.stderr:write("ERROR: ")
- printf(...)
- io.stderr:write("!\n")
- os.exit()
- end
- function warn(...)
- local s = string.format(...)
- io.stderr:write("WARNING: ", s, "\n")
- end
- function remote(...)
- local s = string.format(...)
- s = string.gsub(s, "\n", ";")
- s = string.gsub(s, "%s+", " ")
- s = string.gsub(s, "^%s*", "")
- control:send(s .. "\n")
- control:receive()
- end
- function test(test)
- io.stderr:write("----------------------------------------------\n",
- "testing: ", test, "\n",
- "----------------------------------------------\n")
- end
- function check_timeout(tm, sl, elapsed, err, opp, mode, alldone)
- if tm < sl then
- if opp == "send" then
- if not err then warn("must be buffered")
- elseif err == "timeout" then pass("proper timeout")
- else fail("unexpected error '%s'", err) end
- else
- if err ~= "timeout" then fail("should have timed out")
- else pass("proper timeout") end
- end
- else
- if mode == "total" then
- if elapsed > tm then
- if err ~= "timeout" then fail("should have timed out")
- else pass("proper timeout") end
- elseif elapsed < tm then
- if err then fail(err)
- else pass("ok") end
- else
- if alldone then
- if err then fail("unexpected error '%s'", err)
- else pass("ok") end
- else
- if err ~= "timeout" then fail(err)
- else pass("proper timeoutk") end
- end
- end
- else
- if err then fail(err)
- else pass("ok") end
- end
- end
- end
- if not socket._DEBUG then
- fail("Please define LUASOCKET_DEBUG and recompile LuaSocket")
- end
- io.stderr:write("----------------------------------------------\n",
- "LuaSocket Test Procedures\n",
- "----------------------------------------------\n")
- start = socket.gettime()
- function reconnect()
- if data then data:close() end
- remote [[
- if data then data:close() data = nil end
- data = server:accept()
- data:setoption("tcp-nodelay", true)
- ]]
- data, err = socket.connect(host, port)
- if not data then fail(err) end
- data:setoption("tcp-nodelay", true)
- end
- printf("attempting control connection...")
- control, err = socket.connect(host, port)
- if err then fail(err)
- else pass("connected!") end
- control:setoption("tcp-nodelay", true)
- ------------------------------------------------------------------------
- function test_methods(sock, methods)
- for _, v in pairs(methods) do
- if type(sock[v]) ~= "function" then
- fail(sock.class .. " method '" .. v .. "' not registered")
- end
- end
- pass(sock.class .. " methods are ok")
- end
- ------------------------------------------------------------------------
- function test_mixed(len)
- reconnect()
- io.stderr:write("length " .. len .. ": ")
- local inter = math.ceil(len/4)
- local p1 = "unix " .. string.rep("x", inter) .. "line\n"
- local p2 = "dos " .. string.rep("y", inter) .. "line\r\n"
- local p3 = "raw " .. string.rep("z", inter) .. "bytes"
- local p4 = "end" .. string.rep("w", inter) .. "bytes"
- local bp1, bp2, bp3, bp4
- remote (string.format("str = data:receive(%d)",
- string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4)))
- sent, err = data:send(p1..p2..p3..p4)
- if err then fail(err) end
- remote "data:send(str); data:close()"
- bp1, err = data:receive()
- if err then fail(err) end
- bp2, err = data:receive()
- if err then fail(err) end
- bp3, err = data:receive(string.len(p3))
- if err then fail(err) end
- bp4, err = data:receive("*a")
- if err then fail(err) end
- if bp1.."\n" == p1 and bp2.."\r\n" == p2 and bp3 == p3 and bp4 == p4 then
- pass("patterns match")
- else fail("patterns don't match") end
- end
- ------------------------------------------------------------------------
- if not math.mod then
- math.mod = math.fmod
- end
- function test_asciiline(len)
- reconnect()
- io.stderr:write("length " .. len .. ": ")
- local str, str10, back, err
- str = string.rep("x", math.mod(len, 10))
- str10 = string.rep("aZb.c#dAe?", math.floor(len/10))
- str = str .. str10
- remote "str = data:receive()"
- sent, err = data:send(str.."\n")
- if err then fail(err) end
- remote "data:send(str ..'\\n')"
- back, err = data:receive()
- if err then fail(err) end
- if back == str then pass("lines match")
- else fail("lines don't match") end
- end
- ------------------------------------------------------------------------
- function test_rawline(len)
- reconnect()
- io.stderr:write("length " .. len .. ": ")
- local str, str10, back, err
- str = string.rep(string.char(47), math.mod(len, 10))
- str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100),
- math.floor(len/10))
- str = str .. str10
- remote "str = data:receive()"
- sent, err = data:send(str.."\n")
- if err then fail(err) end
- remote "data:send(str..'\\n')"
- back, err = data:receive()
- if err then fail(err) end
- if back == str then pass("lines match")
- else fail("lines don't match") end
- end
- ------------------------------------------------------------------------
- function test_raw(len)
- reconnect()
- io.stderr:write("length " .. len .. ": ")
- local half = math.floor(len/2)
- local s1, s2, back, err
- s1 = string.rep("x", half)
- s2 = string.rep("y", len-half)
- remote (string.format("str = data:receive(%d)", len))
- sent, err = data:send(s1)
- if err then fail(err) end
- sent, err = data:send(s2)
- if err then fail(err) end
- remote "data:send(str)"
- back, err = data:receive(len)
- if err then fail(err) end
- if back == s1..s2 then pass("blocks match")
- else fail("blocks don't match") end
- end
- ------------------------------------------------------------------------
- function test_totaltimeoutreceive(len, tm, sl)
- reconnect()
- local str, err, partial
- printf("%d bytes, %ds total timeout, %ds pause: ", len, tm, sl)
- remote (string.format ([[
- data:settimeout(%d)
- str = string.rep('a', %d)
- data:send(str)
- print('server: sleeping for %ds')
- socket.sleep(%d)
- print('server: woke up')
- data:send(str)
- ]], 2*tm, len, sl, sl))
- data:settimeout(tm, "total")
- local t = socket.gettime()
- str, err, partial, elapsed = data:receive(2*len)
- check_timeout(tm, sl, elapsed, err, "receive", "total",
- string.len(str or partial) == 2*len)
- end
- ------------------------------------------------------------------------
- function test_totaltimeoutsend(len, tm, sl)
- reconnect()
- local str, err, total
- printf("%d bytes, %ds total timeout, %ds pause: ", len, tm, sl)
- remote (string.format ([[
- data:settimeout(%d)
- str = data:receive(%d)
- print('server: sleeping for %ds')
- socket.sleep(%d)
- print('server: woke up')
- str = data:receive(%d)
- ]], 2*tm, len, sl, sl, len))
- data:settimeout(tm, "total")
- str = string.rep("a", 2*len)
- total, err, partial, elapsed = data:send(str)
- check_timeout(tm, sl, elapsed, err, "send", "total",
- total == 2*len)
- end
- ------------------------------------------------------------------------
- function test_blockingtimeoutreceive(len, tm, sl)
- reconnect()
- local str, err, partial
- printf("%d bytes, %ds blocking timeout, %ds pause: ", len, tm, sl)
- remote (string.format ([[
- data:settimeout(%d)
- str = string.rep('a', %d)
- data:send(str)
- print('server: sleeping for %ds')
- socket.sleep(%d)
- print('server: woke up')
- data:send(str)
- ]], 2*tm, len, sl, sl))
- data:settimeout(tm)
- str, err, partial, elapsed = data:receive(2*len)
- check_timeout(tm, sl, elapsed, err, "receive", "blocking",
- string.len(str or partial) == 2*len)
- end
- ------------------------------------------------------------------------
- function test_blockingtimeoutsend(len, tm, sl)
- reconnect()
- local str, err, total
- printf("%d bytes, %ds blocking timeout, %ds pause: ", len, tm, sl)
- remote (string.format ([[
- data:settimeout(%d)
- str = data:receive(%d)
- print('server: sleeping for %ds')
- socket.sleep(%d)
- print('server: woke up')
- str = data:receive(%d)
- ]], 2*tm, len, sl, sl, len))
- data:settimeout(tm)
- str = string.rep("a", 2*len)
- total, err, partial, elapsed = data:send(str)
- check_timeout(tm, sl, elapsed, err, "send", "blocking",
- total == 2*len)
- end
- ------------------------------------------------------------------------
- function empty_connect()
- printf("empty connect: ")
- reconnect()
- if data then data:close() data = nil end
- remote [[
- if data then data:close() data = nil end
- data = server:accept()
- ]]
- data, err = socket.connect("", port)
- if not data then
- pass("ok")
- data = socket.connect(host, port)
- else
- pass("gethostbyname returns localhost on empty string...")
- end
- end
- ------------------------------------------------------------------------
- function isclosed(c)
- return c:getfd() == -1 or c:getfd() == (2^32-1)
- end
- function active_close()
- local tcp = socket.tcp4()
- if isclosed(tcp) then fail("should not be closed") end
- tcp:close()
- if not isclosed(tcp) then fail("should be closed") end
- tcp = socket.tcp()
- if not isclosed(tcp) then fail("should be closed") end
- tcp = nil
- local udp = socket.udp4()
- if isclosed(udp) then fail("should not be closed") end
- udp:close()
- if not isclosed(udp) then fail("should be closed") end
- udp = socket.udp()
- if not isclosed(udp) then fail("should be closed") end
- udp = nil
- pass("ok")
- end
- ------------------------------------------------------------------------
- function test_closed()
- local back, partial, err
- local str = 'little string'
- reconnect()
- printf("trying read detection: ")
- remote (string.format ([[
- data:send('%s')
- data:close()
- data = nil
- ]], str))
- -- try to get a line
- back, err, partial = data:receive()
- if not err then fail("should have gotten 'closed'.")
- elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.")
- elseif str ~= partial then fail("didn't receive partial result.")
- else pass("graceful 'closed' received") end
- reconnect()
- printf("trying write detection: ")
- remote [[
- data:close()
- data = nil
- ]]
- total, err, partial = data:send(string.rep("ugauga", 100000))
- if not err then
- pass("failed: output buffer is at least %d bytes long!", total)
- elseif err ~= "closed" then
- fail("got '"..err.."' instead of 'closed'.")
- else
- pass("graceful 'closed' received after %d bytes were sent", partial)
- end
- end
- ------------------------------------------------------------------------
- function test_selectbugs()
- local r, s, e = socket.select(nil, nil, 0.1)
- assert(type(r) == "table" and type(s) == "table" and
- (e == "timeout" or e == "error"))
- pass("both nil: ok")
- local udp = socket.udp()
- udp:close()
- r, s, e = socket.select({ udp }, { udp }, 0.1)
- assert(type(r) == "table" and type(s) == "table" and
- (e == "timeout" or e == "error"))
- pass("closed sockets: ok")
- e = pcall(socket.select, "wrong", 1, 0.1)
- assert(e == false, tostring(e))
- e = pcall(socket.select, {}, 1, 0.1)
- assert(e == false, tostring(e))
- pass("invalid input: ok")
- local toomany = {}
- for i = 1, socket._SETSIZE+1 do
- toomany[#toomany+1] = socket.udp4()
- end
- if #toomany > socket._SETSIZE then
- local e = pcall(socket.select, toomany, nil, 0.1)
- assert(e == false, tostring(e))
- pass("too many sockets (" .. #toomany .. "): ok")
- else
- pass("unable to create enough sockets (max was "..#toomany..")")
- pass("try using ulimit")
- end
- for _, c in ipairs(toomany) do c:close() end
- end
- ------------------------------------------------------------------------
- function accept_timeout()
- printf("accept with timeout (if it hangs, it failed): ")
- local s, e = socket.bind("*", 0, 0)
- assert(s, e)
- local t = socket.gettime()
- s:settimeout(1)
- local c, e = s:accept()
- assert(not c, "should not accept")
- assert(e == "timeout", string.format("wrong error message (%s)", e))
- t = socket.gettime() - t
- assert(t < 2, string.format("took to long to give up (%gs)", t))
- s:close()
- pass("good")
- end
- ------------------------------------------------------------------------
- function connect_timeout()
- printf("connect with timeout (if it hangs, it failed!): ")
- local t = socket.gettime()
- local c, e = socket.tcp()
- assert(c, e)
- c:settimeout(0.1)
- local t = socket.gettime()
- local r, e = c:connect("10.0.0.1", 81)
- assert(not r, "should not connect")
- assert(socket.gettime() - t < 2, "took too long to give up.")
- c:close()
- pass("ok")
- end
- ------------------------------------------------------------------------
- function accept_errors()
- printf("not listening: ")
- local d, e = socket.bind("*", 0)
- assert(d, e);
- local c, e = socket.tcp();
- assert(c, e);
- d:setfd(c:getfd())
- d:settimeout(2)
- local r, e = d:accept()
- assert(not r and e)
- pass("ok")
- printf("not supported: ")
- local c, e = socket.udp()
- assert(c, e);
- d:setfd(c:getfd())
- local r, e = d:accept()
- assert(not r and e)
- pass("ok")
- end
- ------------------------------------------------------------------------
- function connect_errors()
- printf("connection refused: ")
- local c, e = socket.connect("localhost", 1);
- assert(not c and e)
- pass("ok")
- printf("host not found: ")
- local c, e = socket.connect("host.is.invalid", 1);
- assert(not c and e, e)
- pass("ok")
- end
- ------------------------------------------------------------------------
- function rebind_test()
- local c ,c1 = socket.bind("127.0.0.1", 0)
- if not c then pass ("failed to bind! " .. tostring(c) .. ' ' .. tostring(c1)) return end
- assert(c,c1)
- local i, p = c:getsockname()
- local s, e = socket.tcp()
- assert(s, e)
- s:setoption("reuseaddr", false)
- r, e = s:bind(i, p)
- assert(not r, "managed to rebind!")
- assert(e)
- pass("ok")
- end
- ------------------------------------------------------------------------
- function getstats_test()
- reconnect()
- local t = 0
- for i = 1, 25 do
- local c = math.random(1, 100)
- remote (string.format ([[
- str = data:receive(%d)
- data:send(str)
- ]], c))
- data:send(string.rep("a", c))
- data:receive(c)
- t = t + c
- local r, s, a = data:getstats()
- assert(r == t, "received count failed" .. tostring(r)
- .. "/" .. tostring(t))
- assert(s == t, "sent count failed" .. tostring(s)
- .. "/" .. tostring(t))
- end
- pass("ok")
- end
- ------------------------------------------------------------------------
- function test_nonblocking(size)
- reconnect()
- printf("testing " .. 2*size .. " bytes: ")
- remote(string.format([[
- data:send(string.rep("a", %d))
- socket.sleep(0.5)
- data:send(string.rep("b", %d) .. "\n")
- ]], size, size))
- local err = "timeout"
- local part = ""
- local str
- data:settimeout(0)
- while 1 do
- str, err, part = data:receive("*l", part)
- if err ~= "timeout" then break end
- end
- assert(str == (string.rep("a", size) .. string.rep("b", size)))
- reconnect()
- remote(string.format([[
- str = data:receive(%d)
- socket.sleep(0.5)
- str = data:receive(2*%d, str)
- data:send(str)
- ]], size, size))
- data:settimeout(0)
- local start = 0
- while 1 do
- ret, err, start = data:send(str, start+1)
- if err ~= "timeout" then break end
- end
- data:send("\n")
- data:settimeout(-1)
- local back = data:receive(2*size)
- assert(back == str, "'" .. back .. "' vs '" .. str .. "'")
- pass("ok")
- end
- ------------------------------------------------------------------------
- function test_readafterclose()
- local back, partial, err
- local str = 'little string'
- reconnect()
- printf("trying repeated '*a' pattern")
- remote (string.format ([[
- data:send('%s')
- data:close()
- data = nil
- ]], str))
- back, err, partial = data:receive("*a")
- assert(back == str, "unexpected data read")
- back, err, partial = data:receive("*a")
- assert(back == nil and err == "closed", "should have returned 'closed'")
- pass("ok")
- reconnect()
- printf("trying active close before '*a'")
- remote (string.format ([[
- data:close()
- data = nil
- ]]))
- data:close()
- back, err, partial = data:receive("*a")
- assert(back == nil and err == "closed", "should have returned 'closed'")
- pass("ok")
- reconnect()
- printf("trying active close before '*l'")
- remote (string.format ([[
- data:close()
- data = nil
- ]]))
- data:close()
- back, err, partial = data:receive()
- assert(back == nil and err == "closed", "should have returned 'closed'")
- pass("ok")
- reconnect()
- printf("trying active close before raw 1")
- remote (string.format ([[
- data:close()
- data = nil
- ]]))
- data:close()
- back, err, partial = data:receive(1)
- assert(back == nil and err == "closed", "should have returned 'closed'")
- pass("ok")
- reconnect()
- printf("trying active close before raw 0")
- remote (string.format ([[
- data:close()
- data = nil
- ]]))
- data:close()
- back, err, partial = data:receive(0)
- assert(back == nil and err == "closed", "should have returned 'closed'")
- pass("ok")
- end
- ------------------------------------------------------------------------
- function test_writeafterclose()
- local str = 'little string'
- reconnect()
- remote (string.format ([[
- data:close()
- data = nil
- ]]))
- local sent, err, errsent
- while not err do
- sent, err, errsent, time = data:send(str)
- end
- assert(err == "closed", "got " .. err .. " instead of 'closed'")
- pass("ok")
- end
- ------------------------------------------------------------------------
- function test_partialrecv()
- local str = 'little string'
- reconnect()
- remote([[
- data:send("7890")
- ]])
- data:settimeout(1)
- back, err = data:receive(10, "123456")
- assert(back == "1234567890", "failed on exact mixed length")
- back, err = data:receive(8, "87654321")
- assert(back == "87654321", "failed on exact length")
- back, err = data:receive(4, "87654321")
- assert(back == "87654321", "failed on smaller length")
- pass("ok")
- end
- ------------------------------------------------------------------------
- test("method registration")
- local tcp_methods = {
- "accept",
- "bind",
- "close",
- "connect",
- "dirty",
- "getfamily",
- "getfd",
- "getoption",
- "getpeername",
- "getsockname",
- "getstats",
- "setstats",
- "listen",
- "receive",
- "send",
- "setfd",
- "setoption",
- "setpeername",
- "setsockname",
- "settimeout",
- "shutdown",
- }
- test_methods(socket.tcp(), tcp_methods)
- do local sock = socket.tcp6()
- if sock then test_methods(socket.tcp6(), tcp_methods)
- else io.stderr:write("Warning! IPv6 does not support!\n") end
- end
- local udp_methods = {
- "close",
- "dirty",
- "getfamily",
- "getfd",
- "getoption",
- "getpeername",
- "getsockname",
- "receive",
- "receivefrom",
- "send",
- "sendto",
- "setfd",
- "setoption",
- "setpeername",
- "setsockname",
- "settimeout"
- }
- ------------------------------------------------------------------------
- test_methods(socket.udp(), udp_methods)
- do local sock = socket.tcp6()
- if sock then test_methods(socket.udp6(), udp_methods)
- else io.stderr:write("Warning! IPv6 does not support!\n") end
- end
- test("closed connection detection: ")
- test_closed()
- test("partial receive")
- test_partialrecv()
- test("select function")
- test_selectbugs()
- test("read after close")
- test_readafterclose()
- test("write after close")
- test_writeafterclose()
- test("connect function")
- connect_timeout()
- empty_connect()
- connect_errors()
- test("rebinding: ")
- rebind_test()
- test("active close: ")
- active_close()
- test("accept function: ")
- accept_timeout()
- accept_errors()
- test("getstats test")
- getstats_test()
- test("character line")
- test_asciiline(1)
- test_asciiline(17)
- test_asciiline(200)
- test_asciiline(4091)
- test_asciiline(80199)
- test_asciiline(8000000)
- test_asciiline(80199)
- test_asciiline(4091)
- test_asciiline(200)
- test_asciiline(17)
- test_asciiline(1)
- test("mixed patterns")
- test_mixed(1)
- test_mixed(17)
- test_mixed(200)
- test_mixed(4091)
- test_mixed(801990)
- test_mixed(4091)
- test_mixed(200)
- test_mixed(17)
- test_mixed(1)
- test("binary line")
- test_rawline(1)
- test_rawline(17)
- test_rawline(200)
- test_rawline(4091)
- test_rawline(80199)
- test_rawline(8000000)
- test_rawline(80199)
- test_rawline(4091)
- test_rawline(200)
- test_rawline(17)
- test_rawline(1)
- test("raw transfer")
- test_raw(1)
- test_raw(17)
- test_raw(200)
- test_raw(4091)
- test_raw(80199)
- test_raw(8000000)
- test_raw(80199)
- test_raw(4091)
- test_raw(200)
- test_raw(17)
- test_raw(1)
- test("non-blocking transfer")
- test_nonblocking(1)
- test_nonblocking(17)
- test_nonblocking(200)
- test_nonblocking(4091)
- test_nonblocking(80199)
- test_nonblocking(800000)
- test_nonblocking(80199)
- test_nonblocking(4091)
- test_nonblocking(200)
- test_nonblocking(17)
- test_nonblocking(1)
- test("total timeout on send")
- test_totaltimeoutsend(800091, 1, 3)
- test_totaltimeoutsend(800091, 2, 3)
- test_totaltimeoutsend(800091, 5, 2)
- test_totaltimeoutsend(800091, 3, 1)
- test("total timeout on receive")
- test_totaltimeoutreceive(800091, 1, 3)
- test_totaltimeoutreceive(800091, 2, 3)
- test_totaltimeoutreceive(800091, 3, 2)
- test_totaltimeoutreceive(800091, 3, 1)
- test("blocking timeout on send")
- test_blockingtimeoutsend(800091, 1, 3)
- test_blockingtimeoutsend(800091, 2, 3)
- test_blockingtimeoutsend(800091, 3, 2)
- test_blockingtimeoutsend(800091, 3, 1)
- test("blocking timeout on receive")
- test_blockingtimeoutreceive(800091, 1, 3)
- test_blockingtimeoutreceive(800091, 2, 3)
- test_blockingtimeoutreceive(800091, 3, 2)
- test_blockingtimeoutreceive(800091, 3, 1)
- test("shutting server down")
- reconnect()
- remote("os.exit()")
- test(string.format("done in %.2fs", socket.gettime() - start))
|