local ok, net = pcall(require, "lb:net") if not ok then return end describe("ipaddr", function() test("invalid ipaddr throws", function() assert(not pcall(net.ipaddr, "invalid ip")) end) test("comparison", function() local a = net.ipaddr("10.0.0.1") local b = net.ipaddr("10.0.0.1") local c = net.ipaddr("10.0.0.2") assert(a ~= nil and a ~= {} and a ~= "10.0.0.1" and a ~= 167772161) assert(a == a and a == b and a ~= c and b ~= c and c == c and c ~= a) assert(a <= b and a < c and a <= c and b < c and b <= c and a <= a and c <= c) assert(not (a < b or a > b or a > c or b > c or a >= c or b >= c)) end) test("tostring", function() local ip = net.ipaddr("10.0.0.1") assert(tostring(ip) == "10.0.0.1") end) end) describe("tcp", function() describe("socket", function() test("bind", function() local socket = net.bind_tcp("127.0.0.1") -- binds to the correct port assert(tostring(socket:local_addr():ip()) == "127.0.0.1") assert(socket:local_addr():port() ~= 0) -- should not be able to rebind socket assert(not pcall(socket.bind, socket, net.socketaddr("127.0.0.1"))) end) test("options", function() local socket = net.tcp() -- keepalive socket:set_keepalive(true) assert(socket:keepalive() == true) socket:set_keepalive(false) assert(socket:keepalive() == false) -- reuseaddr socket:set_reuseaddr(true) assert(socket:reuseaddr() == true) socket:set_reuseaddr(false) assert(socket:reuseaddr() == false) -- reuseport not always supported on all platforms -- sendbuf socket:set_sendbuf(4096) assert(socket:sendbuf() >= 4096) assert(not pcall(socket.set_sendbuf, socket, 0)) assert(not pcall(socket.set_sendbuf, socket, -1)) -- recvbuf socket:set_recvbuf(4096) assert(socket:recvbuf() >= 4096) assert(not pcall(socket.set_recvbuf, socket, 0)) assert(not pcall(socket.set_recvbuf, socket, -1)) -- linger socket:set_linger(0) assert(socket:linger() == 0) socket:set_linger(2) assert(math.abs(socket:linger() - 2) < 0.1) socket:set_linger(-1) assert(socket:linger() == 0) -- nodelay socket:set_nodelay(true) assert(socket:nodelay() == true) socket:set_nodelay(false) assert(socket:nodelay() == false) end) test("can't use socket after conversion", function() local socket = net.tcp() socket:bind(net.socketaddr("127.0.0.1")) socket:listen(10) -- convert to listener assert(not pcall(socket.listen, socket, 10)) -- socket consumed assert(not pcall(socket.local_addr, socket)) end) end) describe("stream", function() test("no concurrent two reads/writes", function() local listener = net.listen_tcp(net.localhost()) local client = net.connect_tcp(listener:local_addr()) local server = listener() local reader = spawn(function() assert(client:read(1) == nil) -- this should block first, then return nil from disconnection end) spawn(function() assert(not pcall(client.read, client, 1)) -- this should fail, since the first task is still reading end):await() server:shutdown() reader:await() end) test("allow concurrent read/write", function() local listener = net.listen_tcp(net.localhost()) local client = net.connect_tcp(listener:local_addr()) local server = listener() local reader = spawn(function() assert(client:read(1) == nil) -- this should block first, then return nil from disconnection end) spawn(function() client:write("hello") -- should be able to write while the first task is reading end):await() server:shutdown() reader:await() end) test("stop reading from disconnected stream", function() local listener = net.listen_tcp(net.localhost()) local client = net.connect_tcp(listener:local_addr()) local server = listener() local reader = spawn(function() while client:read(4) ~= nil do end assert(client:try_read(4) == nil) assert(client:read_partial(4) == nil) assert(client:read(4) == nil) end) for _ = 1, 10 do assert(server:write("ping") == true) end sleep(100) server:shutdown() server = nil collectgarbage() reader:await() end) test("stop writing to disconnected stream", function() local listener = net.listen_tcp(net.localhost()) local client = net.connect_tcp(listener:local_addr()) local server = listener() local writer = spawn(function() while client:write("pong") do end assert(client:try_write("pong") == nil) assert(client:write_partial("pong") == nil) assert(client:write("pong") == false) end) for _ = 1, 10 do assert(server:read(4) == "pong") end sleep(100) server:shutdown() server = nil collectgarbage() writer:await() end) end) describe("listener", function() test("accept", function() local listener = net.listen_tcp(net.localhost()) local addr = listener:local_addr() local accepted = false local client = net.tcp() local accepted_stream listener:on_accept(function(stream) accepted = true accepted_stream = stream -- configure stream stream:set_nodelay(true) assert(stream:nodelay() == true) end) -- connect client local client_stream = client:connect(addr) local server_stream = listener() assert(accepted) assert(accepted_stream ~= nil) -- check addresses assert(server_stream:local_addr() ~= nil) assert(server_stream:peer_addr() ~= nil) assert(client_stream:local_addr() ~= nil) assert(client_stream:peer_addr() ~= nil) -- test data transfer server_stream:write("hello") local buf = client_stream:read(5) assert(buf ~= nil and #buf == 5) assert(buf == "hello") -- shutdown server_stream:shutdown() client_stream:shutdown() end) end) end)