mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-09-12 00:26:38 +00:00
tests: reproduce RSLV fan-out, proxy stuck session
This commit is contained in:
@@ -11,7 +11,10 @@
|
||||
|
||||
module RSLVTests (rslvTests) where
|
||||
|
||||
import Control.Concurrent (threadDelay)
|
||||
import Control.Monad (forM_)
|
||||
import Control.Monad.Trans.Except (ExceptT, runExceptT)
|
||||
import Data.IORef (readIORef)
|
||||
import qualified Data.Aeson as J
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import qualified Data.ByteString.Lazy as LB
|
||||
@@ -82,6 +85,23 @@ rslvTests = do
|
||||
it "PFWD-wrapped RSLV success returns RNAME (record JSON frames over the proxy)" testRslvForwardedSuccess
|
||||
describe "RSLV success path (RNAME response)" $ do
|
||||
it "returns RNAME with NameRecord" testRslvSuccess
|
||||
describe "RSLV resource use" $
|
||||
xit "one connection must not fan out to many concurrent resolver requests" testRslvFanOut
|
||||
|
||||
testRslvFanOut :: IO ()
|
||||
testRslvFanOut =
|
||||
NRS.withResolverServerDelayed 3000 (NRS.resolveResp status200 "{}") $ \port reqs ->
|
||||
withSmpServerConfigOn (transport @TLS) (withNames port memCfg) testPort $ const $
|
||||
testSMPClient @TLS $ \(h@THandle {params} :: THandleSMP TLS 'TClient) -> do
|
||||
let k = 64 :: Int
|
||||
globalCap = 8 :: Int
|
||||
forM_ [1 .. k] $ \i -> do
|
||||
let TransmissionForAuth {tToSend} = encodeTransmissionForAuth params (CorrId (B.pack $ "fan" <> show i), NoEntity, Cmd SResolver (RSLV (domain "alice.simplex")))
|
||||
[Right ()] <- tPut h (Right (Nothing, tToSend) :| [])
|
||||
pure ()
|
||||
threadDelay 800000
|
||||
inFlight <- length . filter ((== ["resolve"]) . take 1) <$> readIORef reqs
|
||||
inFlight `shouldSatisfy` (<= globalCap)
|
||||
|
||||
testRslvBackendNotFound :: IO ()
|
||||
testRslvBackendNotFound =
|
||||
|
||||
@@ -346,6 +346,17 @@ proxyCfgShortTimeout =
|
||||
nt = NetworkTimeout {backgroundTimeout = 4_000000, interactiveTimeout = 4_000000}
|
||||
in cfg' {smpAgentCfg = aCfg {smpCfg = cCfg {networkConfig = (networkConfig cCfg) {tcpConnectTimeout = nt}}}}
|
||||
|
||||
-- Proxy whose forward (RFWD) response deadline is 1us: every forward to the relay times out
|
||||
-- while the initial relay connect (tcpConnectTimeout) is unaffected, so a session is established
|
||||
-- and then every forward on it fails with a response timeout.
|
||||
proxyCfgForwardTimeout :: AServerConfig
|
||||
proxyCfgForwardTimeout =
|
||||
updateCfg proxyCfg $ \cfg' ->
|
||||
let aCfg = smpAgentCfg cfg'
|
||||
cCfg = smpCfg aCfg
|
||||
nt = NetworkTimeout {backgroundTimeout = 1, interactiveTimeout = 1}
|
||||
in cfg' {smpAgentCfg = aCfg {smpCfg = cCfg {networkConfig = (networkConfig cCfg) {tcpTimeout = nt}}}}
|
||||
|
||||
withSmpServerStoreMsgLogOn :: HasCallStack => (ASrvTransport, AStoreType) -> ServiceName -> (HasCallStack => ThreadId -> IO a) -> IO a
|
||||
withSmpServerStoreMsgLogOn (t, msType) =
|
||||
withSmpServerConfigOn t $ updateCfg (cfgMS msType) $ \cfg' -> cfg' {storeNtfsFile = Just testStoreNtfsFile, serverStatsBackupFile = Just testServerStatsBackupFile}
|
||||
|
||||
@@ -63,6 +63,8 @@ smpProxyTests = do
|
||||
testProxyRecoversWithoutDisconnect
|
||||
it "reconnects to relay after sender disconnects mid-connection" $ \_ ->
|
||||
testProxyReconnectAfterRelayRestart
|
||||
xit "must drop a stuck relay session after forward timeouts" $ \_ ->
|
||||
testProxyForwardTimeoutStuckSession
|
||||
describe "agent client reconnection" $ do
|
||||
it "reconnects after a connect is cancelled mid-flight" $ \_ ->
|
||||
testAgentClientReconnectAfterCancel
|
||||
@@ -494,6 +496,19 @@ testProxyReconnectAfterRelayRestart =
|
||||
race_ (threadDelay 1000000) requestRelaySession
|
||||
requireProxyReconnect
|
||||
|
||||
testProxyForwardTimeoutStuckSession :: IO ()
|
||||
testProxyForwardTimeoutStuckSession =
|
||||
withSmpServerConfigOn (transport @TLS) proxyCfgForwardTimeout testPort $ \_ -> do
|
||||
g <- C.newRandom
|
||||
ts <- getCurrentTime
|
||||
let srv = SMPServer testHost testPort testKeyHash
|
||||
vr = mkVersionRange minServerSMPRelayVersion currentClientSMPRelayVersion
|
||||
pc <- either (fail . show) pure =<< getProtocolClient g NRMInteractive (1, srv, Nothing) defaultSMPClientConfig {serverVRange = vr} [] Nothing ts (\_ -> pure ())
|
||||
sess <- runExceptT' $ connectSMPProxiedRelay pc NRMInteractive srv (Just "correct")
|
||||
sId <- atomically $ SMP.EntityId <$> C.randomBytes 24 g
|
||||
rs <- forM ([1 .. 10] :: [Int]) $ \_ -> runExceptT' (proxySMPMessage pc NRMInteractive sess Nothing sId noMsgFlags "hi")
|
||||
rs `shouldSatisfy` elem (Left (ProxyProtocolError (SMP.PROXY SMP.NO_SESSION)))
|
||||
|
||||
-- Bug B (same root cause as the proxy, in the messaging agent): getSMPServerClient inserts an
|
||||
-- empty SessionVar into smpClients, then connects inside newProtocolClient's tryAllErrors, which
|
||||
-- rethrows async exceptions. If the connecting thread is cancelled mid-connect, putTMVar is
|
||||
|
||||
Reference in New Issue
Block a user