From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtpng3.m.smailru.net (smtpng3.m.smailru.net [94.100.177.149]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 56D7546971A for ; Wed, 4 Dec 2019 16:43:25 +0300 (MSK) From: Ilya Kosarev Date: Wed, 4 Dec 2019 16:43:20 +0300 Message-Id: <20191204134320.27760-1-i.kosarev@tarantool.org> Subject: [Tarantool-patches] [PATCH] test: fix flaky socket test List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: tarantool-patches@dev.tarantool.org Cc: v.shpilevoy@tarantool.org socket.test had a number of flaky problems: - socket readableness expectation - race conditions on socket shutdown in emulation test cases - tcp_server stability in socket receive inconsistent behavior case Now they are solved. Port randomization is improved. Socket test is not fragile anymore. Closes #4451, #4426, #4469 --- Branch: https://github.com/tarantool/tarantool/tree/i.kosarev/gh-4426-4451-fix-socket-test Issues: https://github.com/tarantool/tarantool/issues/4426 https://github.com/tarantool/tarantool/issues/4451 https://github.com/tarantool/tarantool/issues/4469 test/app/socket.result | 84 +++++++++++++++++++++++++--------------- test/app/socket.test.lua | 60 +++++++++++++++++++--------- test/app/suite.ini | 1 - 3 files changed, 94 insertions(+), 51 deletions(-) diff --git a/test/app/socket.result b/test/app/socket.result index fd299424c9..42dde8f375 100644 --- a/test/app/socket.result +++ b/test/app/socket.result @@ -45,6 +45,9 @@ test_run:cmd("push filter '(error: .builtin/.*[.]lua):[0-9]+' to '\\1'") WAIT_COND_TIME = 10 --- ... +WAIT_TCP_CONNECT_TIME = 240 +--- +... socket('PF_INET', 'SOCK_STREAM', 'tcp121222'); --- - null @@ -107,7 +110,7 @@ s:nonblock(true) --- - true ... -s:readable(.1) +s:readable(WAIT_TCP_CONNECT_TIME) --- - true ... @@ -227,7 +230,7 @@ s:syswrite(ffi.cast('const char *', ping), #ping) --- - 6 ... -s:readable(1) +s:readable(WAIT_TCP_CONNECT_TIME) --- - true ... @@ -830,7 +833,7 @@ sc:sendto('127.0.0.1', s:name().port, 'Hello, world') --- - 12 ... -s:readable(10) +s:readable(WAIT_TCP_CONNECT_TIME) --- - true ... @@ -842,7 +845,7 @@ sc:sendto('127.0.0.1', s:name().port, 'Hello, world, 2') --- - 15 ... -s:readable(10) +s:readable(WAIT_TCP_CONNECT_TIME) --- - true ... @@ -898,7 +901,7 @@ sc:sendto('127.0.0.1', s:name().port, 'Hello, World!') --- - 13 ... -s:readable(1) +s:readable(WAIT_TCP_CONNECT_TIME) --- - true ... @@ -1074,6 +1077,15 @@ master:setsockopt('SOL_SOCKET', 'SO_REUSEADDR', true) --- - true ... +seed = '' +--- +... +for d in string.gmatch(box.info.uuid, '%d') do seed = seed .. d end +--- +... +math.randomseed(tonumber(seed)) +--- +... port = 32768 + math.random(0, 32767) --- ... @@ -1092,7 +1104,7 @@ test_run:wait_cond(function() return false, master:error() end return true -end, WAIT_COND_TIME); +end, 100); --- - true ... @@ -1822,8 +1834,14 @@ test_run:cmd("setopt delimiter ';'") --- - true ... +socket_opened = true cfiber = fiber.create(function(sc, rch, wch) - while sc:send(wch:get()) and rch:put(sc:receive("*l")) do end + while socket_opened do + sc:send(wch:get()) + local data = sc:receive("*l") + if not socket_opened then sc:close() end + rch:put(data) + end end, sc, rch, wch); --- ... @@ -1936,6 +1954,9 @@ c:receive("*l") --- - ... +socket_opened = false +--- +... wch:put("Fu") --- - true @@ -1944,10 +1965,6 @@ c:send("354 Please type your message\n") --- - 29 ... -sc:close() ---- -- 1 -... c:receive("*l", "Line: ") --- - null @@ -2816,7 +2833,7 @@ test_run:cmd("clear filter") --- - true ... --- case: sicket receive inconsistent behavior +-- case: socket receive inconsistent behavior chan = fiber.channel() --- ... @@ -2826,41 +2843,46 @@ counter = 0 fn = function(s) counter = 0; while true do s:write((tostring(counter)):rep(chan:get())); counter = counter + 1 end end --- ... -srv = socket.tcp_server('0.0.0.0', 8888, fn) +srv = nil --- ... -s = socket.connect('localhost', 8888) +test_run:cmd("setopt delimiter ';'") --- +- true ... -chan:put(5) +test_run:wait_cond(function() + port = 32768 + math.random(0, 32767) + srv = socket.tcp_server('0.0.0.0', port, fn) + return srv ~= nil +end, 100); --- - true ... -chan:put(5) +receive1 = nil; receive2 = nil; --- -- true ... -s:receive(5) +if srv ~= nil then + s = socket.connect('localhost', port) + chan:put(5) + chan:put(5) + receive1 = s:receive(5) + chan:put(5) + s:settimeout(1) + receive2 = s:receive('*a') + s:close() + srv:close() +end; --- -- '00000' ... -chan:put(5) +test_run:cmd("setopt delimiter ''"); --- - true ... -s:settimeout(1) +receive1 --- -- 1 +- '00000' ... -s:receive('*a') +receive2 --- - '1111122222' ... -s:close() ---- -- 1 -... -srv:close() ---- -- true -... diff --git a/test/app/socket.test.lua b/test/app/socket.test.lua index c72d41763f..64f1e07471 100644 --- a/test/app/socket.test.lua +++ b/test/app/socket.test.lua @@ -14,6 +14,7 @@ test_run = env.new() test_run:cmd("push filter '(error: .builtin/.*[.]lua):[0-9]+' to '\\1'") WAIT_COND_TIME = 10 +WAIT_TCP_CONNECT_TIME = 240 socket('PF_INET', 'SOCK_STREAM', 'tcp121222'); @@ -39,7 +40,7 @@ s:nonblock(false) s:nonblock() s:nonblock(true) -s:readable(.1) +s:readable(WAIT_TCP_CONNECT_TIME) s:wait(.1) socket.iowait(s:fd(), 'RW') socket.iowait(s:fd(), 3) @@ -75,7 +76,7 @@ ping = msgpack.encode(string.len(ping)) .. ping -- test syswrite with char * s:syswrite(ffi.cast('const char *', ping), #ping) -s:readable(1) +s:readable(WAIT_TCP_CONNECT_TIME) s:wait(.01) pong = s:sysread() @@ -266,11 +267,11 @@ s = socket('AF_INET', 'SOCK_DGRAM', 'udp') s:bind('127.0.0.1', 0) sc = socket('AF_INET', 'SOCK_DGRAM', 'udp') sc:sendto('127.0.0.1', s:name().port, 'Hello, world') -s:readable(10) +s:readable(WAIT_TCP_CONNECT_TIME) s:recv() sc:sendto('127.0.0.1', s:name().port, 'Hello, world, 2') -s:readable(10) +s:readable(WAIT_TCP_CONNECT_TIME) d, from = s:recvfrom() from.port > 0 from.port = 'Random port' @@ -286,7 +287,7 @@ sc = socket('AF_INET', 'SOCK_DGRAM', 'udp') sc:nonblock(true) sc:sendto('127.0.0.1', s:name().port) sc:sendto('127.0.0.1', s:name().port, 'Hello, World!') -s:readable(1) +s:readable(WAIT_TCP_CONNECT_TIME) data, from = s:recvfrom(10) data s:sendto(from.host, from.port, 'Hello, hello!') @@ -343,6 +344,9 @@ s = nil -- random port master = socket('PF_INET', 'SOCK_STREAM', 'tcp') master:setsockopt('SOL_SOCKET', 'SO_REUSEADDR', true) +seed = '' +for d in string.gmatch(box.info.uuid, '%d') do seed = seed .. d end +math.randomseed(tonumber(seed)) port = 32768 + math.random(0, 32767) -- SO_REUSEADDR allows to bind to the same source addr:port twice, -- so listen() can return EADDRINUSE and so we check it within @@ -356,7 +360,7 @@ test_run:wait_cond(function() return false, master:error() end return true -end, WAIT_COND_TIME); +end, 100); function gh361() local s = socket('PF_INET', 'SOCK_STREAM', 'tcp') s:sysconnect('127.0.0.1', port) @@ -619,8 +623,14 @@ s:settimeout(100500) rch, wch = fiber.channel(1), fiber.channel(1) sc = socket.connect(host, port) test_run:cmd("setopt delimiter ';'") +socket_opened = true cfiber = fiber.create(function(sc, rch, wch) - while sc:send(wch:get()) and rch:put(sc:receive("*l")) do end + while socket_opened do + sc:send(wch:get()) + local data = sc:receive("*l") + if not socket_opened then sc:close() end + rch:put(data) + end end, sc, rch, wch); test_run:cmd("setopt delimiter ''"); @@ -651,9 +661,9 @@ rch:get() wch:put("DATA\n") c:receive(4) c:receive("*l") +socket_opened = false wch:put("Fu") c:send("354 Please type your message\n") -sc:close() c:receive("*l", "Line: ") c:receive() c:receive(10) @@ -960,18 +970,30 @@ server:close() test_run:cmd("clear filter") --- case: sicket receive inconsistent behavior +-- case: socket receive inconsistent behavior chan = fiber.channel() counter = 0 fn = function(s) counter = 0; while true do s:write((tostring(counter)):rep(chan:get())); counter = counter + 1 end end -srv = socket.tcp_server('0.0.0.0', 8888, fn) -s = socket.connect('localhost', 8888) -chan:put(5) -chan:put(5) -s:receive(5) -chan:put(5) -s:settimeout(1) -s:receive('*a') -s:close() -srv:close() +srv = nil +test_run:cmd("setopt delimiter ';'") +test_run:wait_cond(function() + port = 32768 + math.random(0, 32767) + srv = socket.tcp_server('0.0.0.0', port, fn) + return srv ~= nil +end, 100); +receive1 = nil; receive2 = nil; +if srv ~= nil then + s = socket.connect('localhost', port) + chan:put(5) + chan:put(5) + receive1 = s:receive(5) + chan:put(5) + s:settimeout(1) + receive2 = s:receive('*a') + s:close() + srv:close() +end; +test_run:cmd("setopt delimiter ''"); +receive1 +receive2 diff --git a/test/app/suite.ini b/test/app/suite.ini index 79432e29a7..dd802d98cf 100644 --- a/test/app/suite.ini +++ b/test/app/suite.ini @@ -7,4 +7,3 @@ use_unix_sockets = True use_unix_sockets_iproto = True is_parallel = True pretest_clean = True -fragile = socket.test.lua ; gh-4426 gh-4451 -- 2.17.1